aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpuidle
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/cpuidle')
-rw-r--r--drivers/cpuidle/cpuidle.c48
-rw-r--r--drivers/cpuidle/governors/ladder.c5
-rw-r--r--drivers/cpuidle/governors/menu.c4
-rw-r--r--drivers/cpuidle/sysfs.c21
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
181EXPORT_SYMBOL_GPL(cpuidle_disable_device); 182EXPORT_SYMBOL_GPL(cpuidle_disable_device);
182 183
184#ifdef CONFIG_ARCH_HAS_CPU_RELAX
185static 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
205static 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
219static 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) 309static 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
278static void inline cpuidle_free_state_kobj(struct cpuidle_device *device, int i) 278static 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}