diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-07 13:13:52 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-07 13:13:52 -0500 |
commit | 3c00303206c3a1ccd86579efdc90bc35f140962e (patch) | |
tree | 66170c84b5ddaeb102aea3530517a26657b6ea29 /drivers/cpuidle/cpuidle.c | |
parent | 83dbb15e9cd78a3619e3db36777e2f81d09b2914 (diff) | |
parent | efb90582c575084723cc14302c1300cb26c7e01f (diff) |
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux:
cpuidle: Single/Global registration of idle states
cpuidle: Split cpuidle_state structure and move per-cpu statistics fields
cpuidle: Remove CPUIDLE_FLAG_IGNORE and dev->prepare()
cpuidle: Move dev->last_residency update to driver enter routine; remove dev->last_state
ACPI: Fix CONFIG_ACPI_DOCK=n compiler warning
ACPI: Export FADT pm_profile integer value to userspace
thermal: Prevent polling from happening during system suspend
ACPI: Drop ACPI_NO_HARDWARE_INIT
ACPI atomicio: Convert width in bits to bytes in __acpi_ioremap_fast()
PNPACPI: Simplify disabled resource registration
ACPI: Fix possible recursive locking in hwregs.c
ACPI: use kstrdup()
mrst pmu: update comment
tools/power turbostat: less verbose debugging
Diffstat (limited to 'drivers/cpuidle/cpuidle.c')
-rw-r--r-- | drivers/cpuidle/cpuidle.c | 86 |
1 files changed, 28 insertions, 58 deletions
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index becd6d99203b..06ce2680d00d 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c | |||
@@ -62,8 +62,9 @@ static int __cpuidle_register_device(struct cpuidle_device *dev); | |||
62 | int cpuidle_idle_call(void) | 62 | int cpuidle_idle_call(void) |
63 | { | 63 | { |
64 | struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); | 64 | struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); |
65 | struct cpuidle_driver *drv = cpuidle_get_driver(); | ||
65 | struct cpuidle_state *target_state; | 66 | struct cpuidle_state *target_state; |
66 | int next_state; | 67 | int next_state, entered_state; |
67 | 68 | ||
68 | if (off) | 69 | if (off) |
69 | return -ENODEV; | 70 | return -ENODEV; |
@@ -84,45 +85,36 @@ int cpuidle_idle_call(void) | |||
84 | hrtimer_peek_ahead_timers(); | 85 | hrtimer_peek_ahead_timers(); |
85 | #endif | 86 | #endif |
86 | 87 | ||
87 | /* | ||
88 | * Call the device's prepare function before calling the | ||
89 | * governor's select function. ->prepare gives the device's | ||
90 | * cpuidle driver a chance to update any dynamic information | ||
91 | * of its cpuidle states for the current idle period, e.g. | ||
92 | * state availability, latencies, residencies, etc. | ||
93 | */ | ||
94 | if (dev->prepare) | ||
95 | dev->prepare(dev); | ||
96 | |||
97 | /* ask the governor for the next state */ | 88 | /* ask the governor for the next state */ |
98 | next_state = cpuidle_curr_governor->select(dev); | 89 | next_state = cpuidle_curr_governor->select(drv, dev); |
99 | if (need_resched()) { | 90 | if (need_resched()) { |
100 | local_irq_enable(); | 91 | local_irq_enable(); |
101 | return 0; | 92 | return 0; |
102 | } | 93 | } |
103 | 94 | ||
104 | target_state = &dev->states[next_state]; | 95 | target_state = &drv->states[next_state]; |
105 | |||
106 | /* enter the state and update stats */ | ||
107 | dev->last_state = target_state; | ||
108 | 96 | ||
109 | trace_power_start(POWER_CSTATE, next_state, dev->cpu); | 97 | trace_power_start(POWER_CSTATE, next_state, dev->cpu); |
110 | trace_cpu_idle(next_state, dev->cpu); | 98 | trace_cpu_idle(next_state, dev->cpu); |
111 | 99 | ||
112 | dev->last_residency = target_state->enter(dev, target_state); | 100 | entered_state = target_state->enter(dev, drv, next_state); |
113 | 101 | ||
114 | trace_power_end(dev->cpu); | 102 | trace_power_end(dev->cpu); |
115 | trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu); | 103 | trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu); |
116 | 104 | ||
117 | if (dev->last_state) | 105 | if (entered_state >= 0) { |
118 | target_state = dev->last_state; | 106 | /* Update cpuidle counters */ |
119 | 107 | /* This can be moved to within driver enter routine | |
120 | target_state->time += (unsigned long long)dev->last_residency; | 108 | * but that results in multiple copies of same code. |
121 | target_state->usage++; | 109 | */ |
110 | dev->states_usage[entered_state].time += | ||
111 | (unsigned long long)dev->last_residency; | ||
112 | dev->states_usage[entered_state].usage++; | ||
113 | } | ||
122 | 114 | ||
123 | /* give the governor an opportunity to reflect on the outcome */ | 115 | /* give the governor an opportunity to reflect on the outcome */ |
124 | if (cpuidle_curr_governor->reflect) | 116 | if (cpuidle_curr_governor->reflect) |
125 | cpuidle_curr_governor->reflect(dev); | 117 | cpuidle_curr_governor->reflect(dev, entered_state); |
126 | 118 | ||
127 | return 0; | 119 | return 0; |
128 | } | 120 | } |
@@ -173,11 +165,11 @@ void cpuidle_resume_and_unlock(void) | |||
173 | EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock); | 165 | EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock); |
174 | 166 | ||
175 | #ifdef CONFIG_ARCH_HAS_CPU_RELAX | 167 | #ifdef CONFIG_ARCH_HAS_CPU_RELAX |
176 | static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st) | 168 | static int poll_idle(struct cpuidle_device *dev, |
169 | struct cpuidle_driver *drv, int index) | ||
177 | { | 170 | { |
178 | ktime_t t1, t2; | 171 | ktime_t t1, t2; |
179 | s64 diff; | 172 | s64 diff; |
180 | int ret; | ||
181 | 173 | ||
182 | t1 = ktime_get(); | 174 | t1 = ktime_get(); |
183 | local_irq_enable(); | 175 | local_irq_enable(); |
@@ -189,15 +181,14 @@ static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st) | |||
189 | if (diff > INT_MAX) | 181 | if (diff > INT_MAX) |
190 | diff = INT_MAX; | 182 | diff = INT_MAX; |
191 | 183 | ||
192 | ret = (int) diff; | 184 | dev->last_residency = (int) diff; |
193 | return ret; | 185 | |
186 | return index; | ||
194 | } | 187 | } |
195 | 188 | ||
196 | static void poll_idle_init(struct cpuidle_device *dev) | 189 | static void poll_idle_init(struct cpuidle_driver *drv) |
197 | { | 190 | { |
198 | struct cpuidle_state *state = &dev->states[0]; | 191 | struct cpuidle_state *state = &drv->states[0]; |
199 | |||
200 | cpuidle_set_statedata(state, NULL); | ||
201 | 192 | ||
202 | snprintf(state->name, CPUIDLE_NAME_LEN, "POLL"); | 193 | snprintf(state->name, CPUIDLE_NAME_LEN, "POLL"); |
203 | snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE"); | 194 | snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE"); |
@@ -208,7 +199,7 @@ static void poll_idle_init(struct cpuidle_device *dev) | |||
208 | state->enter = poll_idle; | 199 | state->enter = poll_idle; |
209 | } | 200 | } |
210 | #else | 201 | #else |
211 | static void poll_idle_init(struct cpuidle_device *dev) {} | 202 | static void poll_idle_init(struct cpuidle_driver *drv) {} |
212 | #endif /* CONFIG_ARCH_HAS_CPU_RELAX */ | 203 | #endif /* CONFIG_ARCH_HAS_CPU_RELAX */ |
213 | 204 | ||
214 | /** | 205 | /** |
@@ -235,21 +226,20 @@ int cpuidle_enable_device(struct cpuidle_device *dev) | |||
235 | return ret; | 226 | return ret; |
236 | } | 227 | } |
237 | 228 | ||
238 | poll_idle_init(dev); | 229 | poll_idle_init(cpuidle_get_driver()); |
239 | 230 | ||
240 | if ((ret = cpuidle_add_state_sysfs(dev))) | 231 | if ((ret = cpuidle_add_state_sysfs(dev))) |
241 | return ret; | 232 | return ret; |
242 | 233 | ||
243 | if (cpuidle_curr_governor->enable && | 234 | if (cpuidle_curr_governor->enable && |
244 | (ret = cpuidle_curr_governor->enable(dev))) | 235 | (ret = cpuidle_curr_governor->enable(cpuidle_get_driver(), dev))) |
245 | goto fail_sysfs; | 236 | goto fail_sysfs; |
246 | 237 | ||
247 | for (i = 0; i < dev->state_count; i++) { | 238 | for (i = 0; i < dev->state_count; i++) { |
248 | dev->states[i].usage = 0; | 239 | dev->states_usage[i].usage = 0; |
249 | dev->states[i].time = 0; | 240 | dev->states_usage[i].time = 0; |
250 | } | 241 | } |
251 | dev->last_residency = 0; | 242 | dev->last_residency = 0; |
252 | dev->last_state = NULL; | ||
253 | 243 | ||
254 | smp_wmb(); | 244 | smp_wmb(); |
255 | 245 | ||
@@ -283,7 +273,7 @@ void cpuidle_disable_device(struct cpuidle_device *dev) | |||
283 | dev->enabled = 0; | 273 | dev->enabled = 0; |
284 | 274 | ||
285 | if (cpuidle_curr_governor->disable) | 275 | if (cpuidle_curr_governor->disable) |
286 | cpuidle_curr_governor->disable(dev); | 276 | cpuidle_curr_governor->disable(cpuidle_get_driver(), dev); |
287 | 277 | ||
288 | cpuidle_remove_state_sysfs(dev); | 278 | cpuidle_remove_state_sysfs(dev); |
289 | enabled_devices--; | 279 | enabled_devices--; |
@@ -311,26 +301,6 @@ static int __cpuidle_register_device(struct cpuidle_device *dev) | |||
311 | 301 | ||
312 | init_completion(&dev->kobj_unregister); | 302 | init_completion(&dev->kobj_unregister); |
313 | 303 | ||
314 | /* | ||
315 | * cpuidle driver should set the dev->power_specified bit | ||
316 | * before registering the device if the driver provides | ||
317 | * power_usage numbers. | ||
318 | * | ||
319 | * For those devices whose ->power_specified is not set, | ||
320 | * we fill in power_usage with decreasing values as the | ||
321 | * cpuidle code has an implicit assumption that state Cn | ||
322 | * uses less power than C(n-1). | ||
323 | * | ||
324 | * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned | ||
325 | * an power value of -1. So we use -2, -3, etc, for other | ||
326 | * c-states. | ||
327 | */ | ||
328 | if (!dev->power_specified) { | ||
329 | int i; | ||
330 | for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) | ||
331 | dev->states[i].power_usage = -1 - i; | ||
332 | } | ||
333 | |||
334 | per_cpu(cpuidle_devices, dev->cpu) = dev; | 304 | per_cpu(cpuidle_devices, dev->cpu) = dev; |
335 | list_add(&dev->device_list, &cpuidle_detected_devices); | 305 | list_add(&dev->device_list, &cpuidle_detected_devices); |
336 | if ((ret = cpuidle_add_sysfs(sys_dev))) { | 306 | if ((ret = cpuidle_add_sysfs(sys_dev))) { |