aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpuidle/cpuidle.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-03-30 19:45:38 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-30 19:45:39 -0400
commita335750b9a039a9d4cd727cdccacfb90fd63c4e8 (patch)
tree8f3198984fb75fe494e771d9431f6799228623c5 /drivers/cpuidle/cpuidle.c
parent10f3cb41d48ab30f5c754b30eea557371892b4c2 (diff)
parentd326f44e5f2204c7a24db69bfc6dd3fe5f86182b (diff)
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux
Pull ACPI & Power Management changes from Len Brown: - ACPI 5.0 after-ripples, ACPICA/Linux divergence cleanup - cpuidle evolving, more ARM use - thermal sub-system evolving, ditto - assorted other PM bits Fix up conflicts in various cpuidle implementations due to ARM cpuidle cleanups (ARM at91 self-refresh and cpu idle code rewritten into "standby" in asm conflicting with the consolidation of cpuidle time keeping), trivial SH include file context conflict and RCU tracing fixes in generic code. * 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux: (77 commits) ACPI throttling: fix endian bug in acpi_read_throttling_status() Disable MCP limit exceeded messages from Intel IPS driver ACPI video: Don't start video device until its associated input device has been allocated ACPI video: Harden video bus adding. ACPI: Add support for exposing BGRT data ACPI: export acpi_kobj ACPI: Fix logic for removing mappings in 'acpi_unmap' CPER failed to handle generic error records with multiple sections ACPI: Clean redundant codes in scan.c ACPI: Fix unprotected smp_processor_id() in acpi_processor_cst_has_changed() ACPI: consistently use should_use_kmap() PNPACPI: Fix device ref leaking in acpi_pnp_match ACPI: Fix use-after-free in acpi_map_lsapic ACPI: processor_driver: add missing kfree ACPI, APEI: Fix incorrect APEI register bit width check and usage Update documentation for parameter *notrigger* in einj.txt ACPI, APEI, EINJ, new parameter to control trigger action ACPI, APEI, EINJ, limit the range of einj_param ACPI, APEI, Fix ERST header length check cpuidle: power_usage should be declared signed integer ...
Diffstat (limited to 'drivers/cpuidle/cpuidle.c')
-rw-r--r--drivers/cpuidle/cpuidle.c97
1 files changed, 89 insertions, 8 deletions
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 6588f43017bd..87411cebc577 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -53,6 +53,52 @@ 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
74/**
75 * cpuidle_play_dead - cpu off-lining
76 *
77 * Only returns in case of an error
78 */
79int cpuidle_play_dead(void)
80{
81 struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
82 struct cpuidle_driver *drv = cpuidle_get_driver();
83 int i, dead_state = -1;
84 int power_usage = -1;
85
86 /* Find lowest-power state that supports long-term idle */
87 for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
88 struct cpuidle_state *s = &drv->states[i];
89
90 if (s->power_usage < power_usage && s->enter_dead) {
91 power_usage = s->power_usage;
92 dead_state = i;
93 }
94 }
95
96 if (dead_state != -1)
97 return drv->states[dead_state].enter_dead(dev, dead_state);
98
99 return -ENODEV;
100}
101
56/** 102/**
57 * cpuidle_idle_call - the main idle loop 103 * cpuidle_idle_call - the main idle loop
58 * 104 *
@@ -63,7 +109,6 @@ int cpuidle_idle_call(void)
63{ 109{
64 struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); 110 struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
65 struct cpuidle_driver *drv = cpuidle_get_driver(); 111 struct cpuidle_driver *drv = cpuidle_get_driver();
66 struct cpuidle_state *target_state;
67 int next_state, entered_state; 112 int next_state, entered_state;
68 113
69 if (off) 114 if (off)
@@ -92,12 +137,10 @@ int cpuidle_idle_call(void)
92 return 0; 137 return 0;
93 } 138 }
94 139
95 target_state = &drv->states[next_state];
96
97 trace_power_start_rcuidle(POWER_CSTATE, next_state, dev->cpu); 140 trace_power_start_rcuidle(POWER_CSTATE, next_state, dev->cpu);
98 trace_cpu_idle_rcuidle(next_state, dev->cpu); 141 trace_cpu_idle_rcuidle(next_state, dev->cpu);
99 142
100 entered_state = target_state->enter(dev, drv, next_state); 143 entered_state = cpuidle_enter_ops(dev, drv, next_state);
101 144
102 trace_power_end_rcuidle(dev->cpu); 145 trace_power_end_rcuidle(dev->cpu);
103 trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); 146 trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
@@ -110,6 +153,8 @@ int cpuidle_idle_call(void)
110 dev->states_usage[entered_state].time += 153 dev->states_usage[entered_state].time +=
111 (unsigned long long)dev->last_residency; 154 (unsigned long long)dev->last_residency;
112 dev->states_usage[entered_state].usage++; 155 dev->states_usage[entered_state].usage++;
156 } else {
157 dev->last_residency = 0;
113 } 158 }
114 159
115 /* give the governor an opportunity to reflect on the outcome */ 160 /* give the governor an opportunity to reflect on the outcome */
@@ -164,6 +209,37 @@ void cpuidle_resume_and_unlock(void)
164 209
165EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock); 210EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
166 211
212/**
213 * cpuidle_wrap_enter - performs timekeeping and irqen around enter function
214 * @dev: pointer to a valid cpuidle_device object
215 * @drv: pointer to a valid cpuidle_driver object
216 * @index: index of the target cpuidle state.
217 */
218int cpuidle_wrap_enter(struct cpuidle_device *dev,
219 struct cpuidle_driver *drv, int index,
220 int (*enter)(struct cpuidle_device *dev,
221 struct cpuidle_driver *drv, int index))
222{
223 ktime_t time_start, time_end;
224 s64 diff;
225
226 time_start = ktime_get();
227
228 index = enter(dev, drv, index);
229
230 time_end = ktime_get();
231
232 local_irq_enable();
233
234 diff = ktime_to_us(ktime_sub(time_end, time_start));
235 if (diff > INT_MAX)
236 diff = INT_MAX;
237
238 dev->last_residency = (int) diff;
239
240 return index;
241}
242
167#ifdef CONFIG_ARCH_HAS_CPU_RELAX 243#ifdef CONFIG_ARCH_HAS_CPU_RELAX
168static int poll_idle(struct cpuidle_device *dev, 244static int poll_idle(struct cpuidle_device *dev,
169 struct cpuidle_driver *drv, int index) 245 struct cpuidle_driver *drv, int index)
@@ -197,6 +273,7 @@ static void poll_idle_init(struct cpuidle_driver *drv)
197 state->power_usage = -1; 273 state->power_usage = -1;
198 state->flags = 0; 274 state->flags = 0;
199 state->enter = poll_idle; 275 state->enter = poll_idle;
276 state->disable = 0;
200} 277}
201#else 278#else
202static void poll_idle_init(struct cpuidle_driver *drv) {} 279static void poll_idle_init(struct cpuidle_driver *drv) {}
@@ -212,13 +289,14 @@ static void poll_idle_init(struct cpuidle_driver *drv) {}
212int cpuidle_enable_device(struct cpuidle_device *dev) 289int cpuidle_enable_device(struct cpuidle_device *dev)
213{ 290{
214 int ret, i; 291 int ret, i;
292 struct cpuidle_driver *drv = cpuidle_get_driver();
215 293
216 if (dev->enabled) 294 if (dev->enabled)
217 return 0; 295 return 0;
218 if (!cpuidle_get_driver() || !cpuidle_curr_governor) 296 if (!drv || !cpuidle_curr_governor)
219 return -EIO; 297 return -EIO;
220 if (!dev->state_count) 298 if (!dev->state_count)
221 return -EINVAL; 299 dev->state_count = drv->state_count;
222 300
223 if (dev->registered == 0) { 301 if (dev->registered == 0) {
224 ret = __cpuidle_register_device(dev); 302 ret = __cpuidle_register_device(dev);
@@ -226,13 +304,16 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
226 return ret; 304 return ret;
227 } 305 }
228 306
229 poll_idle_init(cpuidle_get_driver()); 307 cpuidle_enter_ops = drv->en_core_tk_irqen ?
308 cpuidle_enter_tk : cpuidle_enter;
309
310 poll_idle_init(drv);
230 311
231 if ((ret = cpuidle_add_state_sysfs(dev))) 312 if ((ret = cpuidle_add_state_sysfs(dev)))
232 return ret; 313 return ret;
233 314
234 if (cpuidle_curr_governor->enable && 315 if (cpuidle_curr_governor->enable &&
235 (ret = cpuidle_curr_governor->enable(cpuidle_get_driver(), dev))) 316 (ret = cpuidle_curr_governor->enable(drv, dev)))
236 goto fail_sysfs; 317 goto fail_sysfs;
237 318
238 for (i = 0; i < dev->state_count; i++) { 319 for (i = 0; i < dev->state_count; i++) {