diff options
Diffstat (limited to 'drivers/cpuidle')
-rw-r--r-- | drivers/cpuidle/cpuidle.c | 48 | ||||
-rw-r--r-- | drivers/cpuidle/governors/ladder.c | 5 | ||||
-rw-r--r-- | drivers/cpuidle/governors/menu.c | 4 | ||||
-rw-r--r-- | drivers/cpuidle/sysfs.c | 21 |
4 files changed, 62 insertions, 16 deletions
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 794962d9f48b..d868d737742f 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c | |||
@@ -12,9 +12,10 @@ | |||
12 | #include <linux/mutex.h> | 12 | #include <linux/mutex.h> |
13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
14 | #include <linux/notifier.h> | 14 | #include <linux/notifier.h> |
15 | #include <linux/latency.h> | 15 | #include <linux/pm_qos_params.h> |
16 | #include <linux/cpu.h> | 16 | #include <linux/cpu.h> |
17 | #include <linux/cpuidle.h> | 17 | #include <linux/cpuidle.h> |
18 | #include <linux/ktime.h> | ||
18 | 19 | ||
19 | #include "cpuidle.h" | 20 | #include "cpuidle.h" |
20 | 21 | ||
@@ -180,6 +181,44 @@ void cpuidle_disable_device(struct cpuidle_device *dev) | |||
180 | 181 | ||
181 | EXPORT_SYMBOL_GPL(cpuidle_disable_device); | 182 | EXPORT_SYMBOL_GPL(cpuidle_disable_device); |
182 | 183 | ||
184 | #ifdef CONFIG_ARCH_HAS_CPU_RELAX | ||
185 | static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st) | ||
186 | { | ||
187 | ktime_t t1, t2; | ||
188 | s64 diff; | ||
189 | int ret; | ||
190 | |||
191 | t1 = ktime_get(); | ||
192 | local_irq_enable(); | ||
193 | while (!need_resched()) | ||
194 | cpu_relax(); | ||
195 | |||
196 | t2 = ktime_get(); | ||
197 | diff = ktime_to_us(ktime_sub(t2, t1)); | ||
198 | if (diff > INT_MAX) | ||
199 | diff = INT_MAX; | ||
200 | |||
201 | ret = (int) diff; | ||
202 | return ret; | ||
203 | } | ||
204 | |||
205 | static void poll_idle_init(struct cpuidle_device *dev) | ||
206 | { | ||
207 | struct cpuidle_state *state = &dev->states[0]; | ||
208 | |||
209 | cpuidle_set_statedata(state, NULL); | ||
210 | |||
211 | snprintf(state->name, CPUIDLE_NAME_LEN, "C0 (poll idle)"); | ||
212 | state->exit_latency = 0; | ||
213 | state->target_residency = 0; | ||
214 | state->power_usage = -1; | ||
215 | state->flags = CPUIDLE_FLAG_POLL | CPUIDLE_FLAG_TIME_VALID; | ||
216 | state->enter = poll_idle; | ||
217 | } | ||
218 | #else | ||
219 | static void poll_idle_init(struct cpuidle_device *dev) {} | ||
220 | #endif /* CONFIG_ARCH_HAS_CPU_RELAX */ | ||
221 | |||
183 | /** | 222 | /** |
184 | * cpuidle_register_device - registers a CPU's idle PM feature | 223 | * cpuidle_register_device - registers a CPU's idle PM feature |
185 | * @dev: the cpu | 224 | * @dev: the cpu |
@@ -198,6 +237,8 @@ int cpuidle_register_device(struct cpuidle_device *dev) | |||
198 | 237 | ||
199 | mutex_lock(&cpuidle_lock); | 238 | mutex_lock(&cpuidle_lock); |
200 | 239 | ||
240 | poll_idle_init(dev); | ||
241 | |||
201 | per_cpu(cpuidle_devices, dev->cpu) = dev; | 242 | per_cpu(cpuidle_devices, dev->cpu) = dev; |
202 | list_add(&dev->device_list, &cpuidle_detected_devices); | 243 | list_add(&dev->device_list, &cpuidle_detected_devices); |
203 | if ((ret = cpuidle_add_sysfs(sys_dev))) { | 244 | if ((ret = cpuidle_add_sysfs(sys_dev))) { |
@@ -265,7 +306,10 @@ static struct notifier_block cpuidle_latency_notifier = { | |||
265 | .notifier_call = cpuidle_latency_notify, | 306 | .notifier_call = cpuidle_latency_notify, |
266 | }; | 307 | }; |
267 | 308 | ||
268 | #define latency_notifier_init(x) do { register_latency_notifier(x); } while (0) | 309 | static inline void latency_notifier_init(struct notifier_block *n) |
310 | { | ||
311 | pm_qos_add_notifier(PM_QOS_CPU_DMA_LATENCY, n); | ||
312 | } | ||
269 | 313 | ||
270 | #else /* CONFIG_SMP */ | 314 | #else /* CONFIG_SMP */ |
271 | 315 | ||
diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c index eb666ecae7c9..ba7b9a6b17a1 100644 --- a/drivers/cpuidle/governors/ladder.c +++ b/drivers/cpuidle/governors/ladder.c | |||
@@ -14,7 +14,7 @@ | |||
14 | 14 | ||
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/cpuidle.h> | 16 | #include <linux/cpuidle.h> |
17 | #include <linux/latency.h> | 17 | #include <linux/pm_qos_params.h> |
18 | #include <linux/moduleparam.h> | 18 | #include <linux/moduleparam.h> |
19 | #include <linux/jiffies.h> | 19 | #include <linux/jiffies.h> |
20 | 20 | ||
@@ -81,7 +81,8 @@ static int ladder_select_state(struct cpuidle_device *dev) | |||
81 | /* consider promotion */ | 81 | /* consider promotion */ |
82 | if (last_idx < dev->state_count - 1 && | 82 | if (last_idx < dev->state_count - 1 && |
83 | last_residency > last_state->threshold.promotion_time && | 83 | last_residency > last_state->threshold.promotion_time && |
84 | dev->states[last_idx + 1].exit_latency <= system_latency_constraint()) { | 84 | dev->states[last_idx + 1].exit_latency <= |
85 | pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY)) { | ||
85 | last_state->stats.promotion_count++; | 86 | last_state->stats.promotion_count++; |
86 | last_state->stats.demotion_count = 0; | 87 | last_state->stats.demotion_count = 0; |
87 | if (last_state->stats.promotion_count >= last_state->threshold.promotion_count) { | 88 | if (last_state->stats.promotion_count >= last_state->threshold.promotion_count) { |
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 299d45c3bdd2..78d77c5dc35c 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c | |||
@@ -8,7 +8,7 @@ | |||
8 | 8 | ||
9 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
10 | #include <linux/cpuidle.h> | 10 | #include <linux/cpuidle.h> |
11 | #include <linux/latency.h> | 11 | #include <linux/pm_qos_params.h> |
12 | #include <linux/time.h> | 12 | #include <linux/time.h> |
13 | #include <linux/ktime.h> | 13 | #include <linux/ktime.h> |
14 | #include <linux/hrtimer.h> | 14 | #include <linux/hrtimer.h> |
@@ -48,7 +48,7 @@ static int menu_select(struct cpuidle_device *dev) | |||
48 | break; | 48 | break; |
49 | if (s->target_residency > data->predicted_us) | 49 | if (s->target_residency > data->predicted_us) |
50 | break; | 50 | break; |
51 | if (s->exit_latency > system_latency_constraint()) | 51 | if (s->exit_latency > pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY)) |
52 | break; | 52 | break; |
53 | } | 53 | } |
54 | 54 | ||
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 0f3515e77d4b..088ea74edd34 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c | |||
@@ -277,7 +277,7 @@ static struct kobj_type ktype_state_cpuidle = { | |||
277 | 277 | ||
278 | static void inline cpuidle_free_state_kobj(struct cpuidle_device *device, int i) | 278 | static void inline cpuidle_free_state_kobj(struct cpuidle_device *device, int i) |
279 | { | 279 | { |
280 | kobject_unregister(&device->kobjs[i]->kobj); | 280 | kobject_put(&device->kobjs[i]->kobj); |
281 | wait_for_completion(&device->kobjs[i]->kobj_unregister); | 281 | wait_for_completion(&device->kobjs[i]->kobj_unregister); |
282 | kfree(device->kobjs[i]); | 282 | kfree(device->kobjs[i]); |
283 | device->kobjs[i] = NULL; | 283 | device->kobjs[i] = NULL; |
@@ -300,14 +300,13 @@ int cpuidle_add_state_sysfs(struct cpuidle_device *device) | |||
300 | kobj->state = &device->states[i]; | 300 | kobj->state = &device->states[i]; |
301 | init_completion(&kobj->kobj_unregister); | 301 | init_completion(&kobj->kobj_unregister); |
302 | 302 | ||
303 | kobj->kobj.parent = &device->kobj; | 303 | ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, &device->kobj, |
304 | kobj->kobj.ktype = &ktype_state_cpuidle; | 304 | "state%d", i); |
305 | kobject_set_name(&kobj->kobj, "state%d", i); | ||
306 | ret = kobject_register(&kobj->kobj); | ||
307 | if (ret) { | 305 | if (ret) { |
308 | kfree(kobj); | 306 | kfree(kobj); |
309 | goto error_state; | 307 | goto error_state; |
310 | } | 308 | } |
309 | kobject_uevent(&kobj->kobj, KOBJ_ADD); | ||
311 | device->kobjs[i] = kobj; | 310 | device->kobjs[i] = kobj; |
312 | } | 311 | } |
313 | 312 | ||
@@ -339,12 +338,14 @@ int cpuidle_add_sysfs(struct sys_device *sysdev) | |||
339 | { | 338 | { |
340 | int cpu = sysdev->id; | 339 | int cpu = sysdev->id; |
341 | struct cpuidle_device *dev; | 340 | struct cpuidle_device *dev; |
341 | int error; | ||
342 | 342 | ||
343 | dev = per_cpu(cpuidle_devices, cpu); | 343 | dev = per_cpu(cpuidle_devices, cpu); |
344 | dev->kobj.parent = &sysdev->kobj; | 344 | error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &sysdev->kobj, |
345 | dev->kobj.ktype = &ktype_cpuidle; | 345 | "cpuidle"); |
346 | kobject_set_name(&dev->kobj, "%s", "cpuidle"); | 346 | if (!error) |
347 | return kobject_register(&dev->kobj); | 347 | kobject_uevent(&dev->kobj, KOBJ_ADD); |
348 | return error; | ||
348 | } | 349 | } |
349 | 350 | ||
350 | /** | 351 | /** |
@@ -357,5 +358,5 @@ void cpuidle_remove_sysfs(struct sys_device *sysdev) | |||
357 | struct cpuidle_device *dev; | 358 | struct cpuidle_device *dev; |
358 | 359 | ||
359 | dev = per_cpu(cpuidle_devices, cpu); | 360 | dev = per_cpu(cpuidle_devices, cpu); |
360 | kobject_unregister(&dev->kobj); | 361 | kobject_put(&dev->kobj); |
361 | } | 362 | } |