aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/cpuidle/Kconfig9
-rw-r--r--drivers/cpuidle/cpuidle.c36
-rw-r--r--drivers/cpuidle/cpuidle.h4
-rw-r--r--drivers/cpuidle/driver.c166
-rw-r--r--drivers/cpuidle/sysfs.c174
-rw-r--r--include/linux/cpuidle.h7
6 files changed, 356 insertions, 40 deletions
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
index a76b689e553b..234ae651b38f 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -9,6 +9,15 @@ config CPU_IDLE
9 9
10 If you're using an ACPI-enabled platform, you should say Y here. 10 If you're using an ACPI-enabled platform, you should say Y here.
11 11
12config CPU_IDLE_MULTIPLE_DRIVERS
13 bool "Support multiple cpuidle drivers"
14 depends on CPU_IDLE
15 default n
16 help
17 Allows the cpuidle framework to use different drivers for each CPU.
18 This is useful if you have a system with different CPU latencies and
19 states. If unsure say N.
20
12config CPU_IDLE_GOV_LADDER 21config CPU_IDLE_GOV_LADDER
13 bool 22 bool
14 depends on CPU_IDLE 23 depends on CPU_IDLE
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index ce4cac706dd1..711dd83fd3ba 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -68,7 +68,7 @@ static cpuidle_enter_t cpuidle_enter_ops;
68int cpuidle_play_dead(void) 68int cpuidle_play_dead(void)
69{ 69{
70 struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); 70 struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
71 struct cpuidle_driver *drv = cpuidle_get_driver(); 71 struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
72 int i, dead_state = -1; 72 int i, dead_state = -1;
73 int power_usage = -1; 73 int power_usage = -1;
74 74
@@ -128,7 +128,7 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
128int cpuidle_idle_call(void) 128int cpuidle_idle_call(void)
129{ 129{
130 struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); 130 struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
131 struct cpuidle_driver *drv = cpuidle_get_driver(); 131 struct cpuidle_driver *drv;
132 int next_state, entered_state; 132 int next_state, entered_state;
133 133
134 if (off) 134 if (off)
@@ -141,6 +141,8 @@ int cpuidle_idle_call(void)
141 if (!dev || !dev->enabled) 141 if (!dev || !dev->enabled)
142 return -EBUSY; 142 return -EBUSY;
143 143
144 drv = cpuidle_get_cpu_driver(dev);
145
144 /* ask the governor for the next state */ 146 /* ask the governor for the next state */
145 next_state = cpuidle_curr_governor->select(drv, dev); 147 next_state = cpuidle_curr_governor->select(drv, dev);
146 if (need_resched()) { 148 if (need_resched()) {
@@ -312,15 +314,19 @@ static void poll_idle_init(struct cpuidle_driver *drv) {}
312int cpuidle_enable_device(struct cpuidle_device *dev) 314int cpuidle_enable_device(struct cpuidle_device *dev)
313{ 315{
314 int ret, i; 316 int ret, i;
315 struct cpuidle_driver *drv = cpuidle_get_driver(); 317 struct cpuidle_driver *drv;
316 318
317 if (!dev) 319 if (!dev)
318 return -EINVAL; 320 return -EINVAL;
319 321
320 if (dev->enabled) 322 if (dev->enabled)
321 return 0; 323 return 0;
324
325 drv = cpuidle_get_cpu_driver(dev);
326
322 if (!drv || !cpuidle_curr_governor) 327 if (!drv || !cpuidle_curr_governor)
323 return -EIO; 328 return -EIO;
329
324 if (!dev->state_count) 330 if (!dev->state_count)
325 dev->state_count = drv->state_count; 331 dev->state_count = drv->state_count;
326 332
@@ -335,7 +341,8 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
335 341
336 poll_idle_init(drv); 342 poll_idle_init(drv);
337 343
338 if ((ret = cpuidle_add_state_sysfs(dev))) 344 ret = cpuidle_add_device_sysfs(dev);
345 if (ret)
339 return ret; 346 return ret;
340 347
341 if (cpuidle_curr_governor->enable && 348 if (cpuidle_curr_governor->enable &&
@@ -356,7 +363,7 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
356 return 0; 363 return 0;
357 364
358fail_sysfs: 365fail_sysfs:
359 cpuidle_remove_state_sysfs(dev); 366 cpuidle_remove_device_sysfs(dev);
360 367
361 return ret; 368 return ret;
362} 369}
@@ -372,17 +379,20 @@ EXPORT_SYMBOL_GPL(cpuidle_enable_device);
372 */ 379 */
373void cpuidle_disable_device(struct cpuidle_device *dev) 380void cpuidle_disable_device(struct cpuidle_device *dev)
374{ 381{
382 struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
383
375 if (!dev || !dev->enabled) 384 if (!dev || !dev->enabled)
376 return; 385 return;
377 if (!cpuidle_get_driver() || !cpuidle_curr_governor) 386
387 if (!drv || !cpuidle_curr_governor)
378 return; 388 return;
379 389
380 dev->enabled = 0; 390 dev->enabled = 0;
381 391
382 if (cpuidle_curr_governor->disable) 392 if (cpuidle_curr_governor->disable)
383 cpuidle_curr_governor->disable(cpuidle_get_driver(), dev); 393 cpuidle_curr_governor->disable(drv, dev);
384 394
385 cpuidle_remove_state_sysfs(dev); 395 cpuidle_remove_device_sysfs(dev);
386 enabled_devices--; 396 enabled_devices--;
387} 397}
388 398
@@ -398,9 +408,9 @@ EXPORT_SYMBOL_GPL(cpuidle_disable_device);
398static int __cpuidle_register_device(struct cpuidle_device *dev) 408static int __cpuidle_register_device(struct cpuidle_device *dev)
399{ 409{
400 int ret; 410 int ret;
401 struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver(); 411 struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
402 412
403 if (!try_module_get(cpuidle_driver->owner)) 413 if (!try_module_get(drv->owner))
404 return -EINVAL; 414 return -EINVAL;
405 415
406 per_cpu(cpuidle_devices, dev->cpu) = dev; 416 per_cpu(cpuidle_devices, dev->cpu) = dev;
@@ -421,7 +431,7 @@ err_coupled:
421err_sysfs: 431err_sysfs:
422 list_del(&dev->device_list); 432 list_del(&dev->device_list);
423 per_cpu(cpuidle_devices, dev->cpu) = NULL; 433 per_cpu(cpuidle_devices, dev->cpu) = NULL;
424 module_put(cpuidle_driver->owner); 434 module_put(drv->owner);
425 return ret; 435 return ret;
426} 436}
427 437
@@ -460,7 +470,7 @@ EXPORT_SYMBOL_GPL(cpuidle_register_device);
460 */ 470 */
461void cpuidle_unregister_device(struct cpuidle_device *dev) 471void cpuidle_unregister_device(struct cpuidle_device *dev)
462{ 472{
463 struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver(); 473 struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
464 474
465 if (dev->registered == 0) 475 if (dev->registered == 0)
466 return; 476 return;
@@ -477,7 +487,7 @@ void cpuidle_unregister_device(struct cpuidle_device *dev)
477 487
478 cpuidle_resume_and_unlock(); 488 cpuidle_resume_and_unlock();
479 489
480 module_put(cpuidle_driver->owner); 490 module_put(drv->owner);
481} 491}
482 492
483EXPORT_SYMBOL_GPL(cpuidle_unregister_device); 493EXPORT_SYMBOL_GPL(cpuidle_unregister_device);
diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h
index f6b0923c2253..ee97e9672ecf 100644
--- a/drivers/cpuidle/cpuidle.h
+++ b/drivers/cpuidle/cpuidle.h
@@ -28,8 +28,8 @@ struct device;
28 28
29extern int cpuidle_add_interface(struct device *dev); 29extern int cpuidle_add_interface(struct device *dev);
30extern void cpuidle_remove_interface(struct device *dev); 30extern void cpuidle_remove_interface(struct device *dev);
31extern int cpuidle_add_state_sysfs(struct cpuidle_device *device); 31extern int cpuidle_add_device_sysfs(struct cpuidle_device *device);
32extern void cpuidle_remove_state_sysfs(struct cpuidle_device *device); 32extern void cpuidle_remove_device_sysfs(struct cpuidle_device *device);
33extern int cpuidle_add_sysfs(struct cpuidle_device *dev); 33extern int cpuidle_add_sysfs(struct cpuidle_device *dev);
34extern void cpuidle_remove_sysfs(struct cpuidle_device *dev); 34extern void cpuidle_remove_sysfs(struct cpuidle_device *dev);
35 35
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c
index 8246662f594a..3af841fb397a 100644
--- a/drivers/cpuidle/driver.c
+++ b/drivers/cpuidle/driver.c
@@ -14,9 +14,11 @@
14 14
15#include "cpuidle.h" 15#include "cpuidle.h"
16 16
17static struct cpuidle_driver *cpuidle_curr_driver;
18DEFINE_SPINLOCK(cpuidle_driver_lock); 17DEFINE_SPINLOCK(cpuidle_driver_lock);
19 18
19static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu);
20static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu);
21
20static void set_power_states(struct cpuidle_driver *drv) 22static void set_power_states(struct cpuidle_driver *drv)
21{ 23{
22 int i; 24 int i;
@@ -47,12 +49,7 @@ static void __cpuidle_driver_init(struct cpuidle_driver *drv)
47 set_power_states(drv); 49 set_power_states(drv);
48} 50}
49 51
50static void cpuidle_set_driver(struct cpuidle_driver *drv) 52static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu)
51{
52 cpuidle_curr_driver = drv;
53}
54
55static int __cpuidle_register_driver(struct cpuidle_driver *drv)
56{ 53{
57 if (!drv || !drv->state_count) 54 if (!drv || !drv->state_count)
58 return -EINVAL; 55 return -EINVAL;
@@ -60,23 +57,84 @@ static int __cpuidle_register_driver(struct cpuidle_driver *drv)
60 if (cpuidle_disabled()) 57 if (cpuidle_disabled())
61 return -ENODEV; 58 return -ENODEV;
62 59
63 if (cpuidle_get_driver()) 60 if (__cpuidle_get_cpu_driver(cpu))
64 return -EBUSY; 61 return -EBUSY;
65 62
66 __cpuidle_driver_init(drv); 63 __cpuidle_driver_init(drv);
67 64
68 cpuidle_set_driver(drv); 65 __cpuidle_set_cpu_driver(drv, cpu);
69 66
70 return 0; 67 return 0;
71} 68}
72 69
73static void __cpuidle_unregister_driver(struct cpuidle_driver *drv) 70static void __cpuidle_unregister_driver(struct cpuidle_driver *drv, int cpu)
74{ 71{
75 if (drv != cpuidle_get_driver()) 72 if (drv != __cpuidle_get_cpu_driver(cpu))
76 return; 73 return;
77 74
78 if (!WARN_ON(drv->refcnt > 0)) 75 if (!WARN_ON(drv->refcnt > 0))
79 cpuidle_set_driver(NULL); 76 __cpuidle_set_cpu_driver(NULL, cpu);
77}
78
79#ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS
80
81static DEFINE_PER_CPU(struct cpuidle_driver *, cpuidle_drivers);
82
83static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu)
84{
85 per_cpu(cpuidle_drivers, cpu) = drv;
86}
87
88static struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
89{
90 return per_cpu(cpuidle_drivers, cpu);
91}
92
93static void __cpuidle_unregister_all_cpu_driver(struct cpuidle_driver *drv)
94{
95 int cpu;
96 for_each_present_cpu(cpu)
97 __cpuidle_unregister_driver(drv, cpu);
98}
99
100static int __cpuidle_register_all_cpu_driver(struct cpuidle_driver *drv)
101{
102 int ret = 0;
103 int i, cpu;
104
105 for_each_present_cpu(cpu) {
106 ret = __cpuidle_register_driver(drv, cpu);
107 if (ret)
108 break;
109 }
110
111 if (ret)
112 for_each_present_cpu(i) {
113 if (i == cpu)
114 break;
115 __cpuidle_unregister_driver(drv, i);
116 }
117
118
119 return ret;
120}
121
122int cpuidle_register_cpu_driver(struct cpuidle_driver *drv, int cpu)
123{
124 int ret;
125
126 spin_lock(&cpuidle_driver_lock);
127 ret = __cpuidle_register_driver(drv, cpu);
128 spin_unlock(&cpuidle_driver_lock);
129
130 return ret;
131}
132
133void cpuidle_unregister_cpu_driver(struct cpuidle_driver *drv, int cpu)
134{
135 spin_lock(&cpuidle_driver_lock);
136 __cpuidle_unregister_driver(drv, cpu);
137 spin_unlock(&cpuidle_driver_lock);
80} 138}
81 139
82/** 140/**
@@ -88,7 +146,7 @@ int cpuidle_register_driver(struct cpuidle_driver *drv)
88 int ret; 146 int ret;
89 147
90 spin_lock(&cpuidle_driver_lock); 148 spin_lock(&cpuidle_driver_lock);
91 ret = __cpuidle_register_driver(drv); 149 ret = __cpuidle_register_all_cpu_driver(drv);
92 spin_unlock(&cpuidle_driver_lock); 150 spin_unlock(&cpuidle_driver_lock);
93 151
94 return ret; 152 return ret;
@@ -96,13 +154,48 @@ int cpuidle_register_driver(struct cpuidle_driver *drv)
96EXPORT_SYMBOL_GPL(cpuidle_register_driver); 154EXPORT_SYMBOL_GPL(cpuidle_register_driver);
97 155
98/** 156/**
99 * cpuidle_get_driver - return the current driver 157 * cpuidle_unregister_driver - unregisters a driver
158 * @drv: the driver
100 */ 159 */
101struct cpuidle_driver *cpuidle_get_driver(void) 160void cpuidle_unregister_driver(struct cpuidle_driver *drv)
161{
162 spin_lock(&cpuidle_driver_lock);
163 __cpuidle_unregister_all_cpu_driver(drv);
164 spin_unlock(&cpuidle_driver_lock);
165}
166EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
167
168#else
169
170static struct cpuidle_driver *cpuidle_curr_driver;
171
172static inline void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu)
173{
174 cpuidle_curr_driver = drv;
175}
176
177static inline struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
102{ 178{
103 return cpuidle_curr_driver; 179 return cpuidle_curr_driver;
104} 180}
105EXPORT_SYMBOL_GPL(cpuidle_get_driver); 181
182/**
183 * cpuidle_register_driver - registers a driver
184 * @drv: the driver
185 */
186int cpuidle_register_driver(struct cpuidle_driver *drv)
187{
188 int ret, cpu;
189
190 cpu = get_cpu();
191 spin_lock(&cpuidle_driver_lock);
192 ret = __cpuidle_register_driver(drv, cpu);
193 spin_unlock(&cpuidle_driver_lock);
194 put_cpu();
195
196 return ret;
197}
198EXPORT_SYMBOL_GPL(cpuidle_register_driver);
106 199
107/** 200/**
108 * cpuidle_unregister_driver - unregisters a driver 201 * cpuidle_unregister_driver - unregisters a driver
@@ -110,11 +203,50 @@ EXPORT_SYMBOL_GPL(cpuidle_get_driver);
110 */ 203 */
111void cpuidle_unregister_driver(struct cpuidle_driver *drv) 204void cpuidle_unregister_driver(struct cpuidle_driver *drv)
112{ 205{
206 int cpu;
207
208 cpu = get_cpu();
113 spin_lock(&cpuidle_driver_lock); 209 spin_lock(&cpuidle_driver_lock);
114 __cpuidle_unregister_driver(drv); 210 __cpuidle_unregister_driver(drv, cpu);
115 spin_unlock(&cpuidle_driver_lock); 211 spin_unlock(&cpuidle_driver_lock);
212 put_cpu();
116} 213}
117EXPORT_SYMBOL_GPL(cpuidle_unregister_driver); 214EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
215#endif
216
217/**
218 * cpuidle_get_driver - return the current driver
219 */
220struct cpuidle_driver *cpuidle_get_driver(void)
221{
222 struct cpuidle_driver *drv;
223 int cpu;
224
225 cpu = get_cpu();
226 drv = __cpuidle_get_cpu_driver(cpu);
227 put_cpu();
228
229 return drv;
230}
231EXPORT_SYMBOL_GPL(cpuidle_get_driver);
232
233/**
234 * cpuidle_get_cpu_driver - return the driver tied with a cpu
235 */
236struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev)
237{
238 struct cpuidle_driver *drv;
239
240 if (!dev)
241 return NULL;
242
243 spin_lock(&cpuidle_driver_lock);
244 drv = __cpuidle_get_cpu_driver(dev->cpu);
245 spin_unlock(&cpuidle_driver_lock);
246
247 return drv;
248}
249EXPORT_SYMBOL_GPL(cpuidle_get_cpu_driver);
118 250
119struct cpuidle_driver *cpuidle_driver_ref(void) 251struct cpuidle_driver *cpuidle_driver_ref(void)
120{ 252{
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index 49b1f4bcc1b3..340942946106 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -364,17 +364,17 @@ static inline void cpuidle_free_state_kobj(struct cpuidle_device *device, int i)
364} 364}
365 365
366/** 366/**
367 * cpuidle_add_driver_sysfs - adds driver-specific sysfs attributes 367 * cpuidle_add_state_sysfs - adds cpuidle states sysfs attributes
368 * @device: the target device 368 * @device: the target device
369 */ 369 */
370int cpuidle_add_state_sysfs(struct cpuidle_device *device) 370static int cpuidle_add_state_sysfs(struct cpuidle_device *device)
371{ 371{
372 int i, ret = -ENOMEM; 372 int i, ret = -ENOMEM;
373 struct cpuidle_state_kobj *kobj; 373 struct cpuidle_state_kobj *kobj;
374 struct cpuidle_driver *drv = cpuidle_get_driver(); 374 struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device);
375 375
376 /* state statistics */ 376 /* state statistics */
377 for (i = 0; i < device->state_count; i++) { 377 for (i = 0; i < drv->state_count; i++) {
378 kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL); 378 kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL);
379 if (!kobj) 379 if (!kobj)
380 goto error_state; 380 goto error_state;
@@ -401,10 +401,10 @@ error_state:
401} 401}
402 402
403/** 403/**
404 * cpuidle_remove_driver_sysfs - removes driver-specific sysfs attributes 404 * cpuidle_remove_driver_sysfs - removes the cpuidle states sysfs attributes
405 * @device: the target device 405 * @device: the target device
406 */ 406 */
407void cpuidle_remove_state_sysfs(struct cpuidle_device *device) 407static void cpuidle_remove_state_sysfs(struct cpuidle_device *device)
408{ 408{
409 int i; 409 int i;
410 410
@@ -412,6 +412,168 @@ void cpuidle_remove_state_sysfs(struct cpuidle_device *device)
412 cpuidle_free_state_kobj(device, i); 412 cpuidle_free_state_kobj(device, i);
413} 413}
414 414
415#ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS
416#define kobj_to_driver_kobj(k) container_of(k, struct cpuidle_driver_kobj, kobj)
417#define attr_to_driver_attr(a) container_of(a, struct cpuidle_driver_attr, attr)
418
419#define define_one_driver_ro(_name, show) \
420 static struct cpuidle_driver_attr attr_driver_##_name = \
421 __ATTR(_name, 0644, show, NULL)
422
423struct cpuidle_driver_kobj {
424 struct cpuidle_driver *drv;
425 struct completion kobj_unregister;
426 struct kobject kobj;
427};
428
429struct cpuidle_driver_attr {
430 struct attribute attr;
431 ssize_t (*show)(struct cpuidle_driver *, char *);
432 ssize_t (*store)(struct cpuidle_driver *, const char *, size_t);
433};
434
435static ssize_t show_driver_name(struct cpuidle_driver *drv, char *buf)
436{
437 ssize_t ret;
438
439 spin_lock(&cpuidle_driver_lock);
440 ret = sprintf(buf, "%s\n", drv ? drv->name : "none");
441 spin_unlock(&cpuidle_driver_lock);
442
443 return ret;
444}
445
446static void cpuidle_driver_sysfs_release(struct kobject *kobj)
447{
448 struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj);
449 complete(&driver_kobj->kobj_unregister);
450}
451
452static ssize_t cpuidle_driver_show(struct kobject *kobj, struct attribute * attr,
453 char * buf)
454{
455 int ret = -EIO;
456 struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj);
457 struct cpuidle_driver_attr *dattr = attr_to_driver_attr(attr);
458
459 if (dattr->show)
460 ret = dattr->show(driver_kobj->drv, buf);
461
462 return ret;
463}
464
465static ssize_t cpuidle_driver_store(struct kobject *kobj, struct attribute *attr,
466 const char *buf, size_t size)
467{
468 int ret = -EIO;
469 struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj);
470 struct cpuidle_driver_attr *dattr = attr_to_driver_attr(attr);
471
472 if (dattr->store)
473 ret = dattr->store(driver_kobj->drv, buf, size);
474
475 return ret;
476}
477
478define_one_driver_ro(name, show_driver_name);
479
480static const struct sysfs_ops cpuidle_driver_sysfs_ops = {
481 .show = cpuidle_driver_show,
482 .store = cpuidle_driver_store,
483};
484
485static struct attribute *cpuidle_driver_default_attrs[] = {
486 &attr_driver_name.attr,
487 NULL
488};
489
490static struct kobj_type ktype_driver_cpuidle = {
491 .sysfs_ops = &cpuidle_driver_sysfs_ops,
492 .default_attrs = cpuidle_driver_default_attrs,
493 .release = cpuidle_driver_sysfs_release,
494};
495
496/**
497 * cpuidle_add_driver_sysfs - adds the driver name sysfs attribute
498 * @device: the target device
499 */
500static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev)
501{
502 struct cpuidle_driver_kobj *kdrv;
503 struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
504 int ret;
505
506 kdrv = kzalloc(sizeof(*kdrv), GFP_KERNEL);
507 if (!kdrv)
508 return -ENOMEM;
509
510 kdrv->drv = drv;
511 init_completion(&kdrv->kobj_unregister);
512
513 ret = kobject_init_and_add(&kdrv->kobj, &ktype_driver_cpuidle,
514 &dev->kobj, "driver");
515 if (ret) {
516 kfree(kdrv);
517 return ret;
518 }
519
520 kobject_uevent(&kdrv->kobj, KOBJ_ADD);
521 dev->kobj_driver = kdrv;
522
523 return ret;
524}
525
526/**
527 * cpuidle_remove_driver_sysfs - removes the driver name sysfs attribute
528 * @device: the target device
529 */
530static void cpuidle_remove_driver_sysfs(struct cpuidle_device *dev)
531{
532 struct cpuidle_driver_kobj *kdrv = dev->kobj_driver;
533 kobject_put(&kdrv->kobj);
534 wait_for_completion(&kdrv->kobj_unregister);
535 kfree(kdrv);
536}
537#else
538static inline int cpuidle_add_driver_sysfs(struct cpuidle_device *dev)
539{
540 return 0;
541}
542
543static inline void cpuidle_remove_driver_sysfs(struct cpuidle_device *dev)
544{
545 ;
546}
547#endif
548
549/**
550 * cpuidle_add_device_sysfs - adds device specific sysfs attributes
551 * @device: the target device
552 */
553int cpuidle_add_device_sysfs(struct cpuidle_device *device)
554{
555 int ret;
556
557 ret = cpuidle_add_state_sysfs(device);
558 if (ret)
559 return ret;
560
561 ret = cpuidle_add_driver_sysfs(device);
562 if (ret)
563 cpuidle_remove_state_sysfs(device);
564 return ret;
565}
566
567/**
568 * cpuidle_remove_device_sysfs : removes device specific sysfs attributes
569 * @device : the target device
570 */
571void cpuidle_remove_device_sysfs(struct cpuidle_device *device)
572{
573 cpuidle_remove_driver_sysfs(device);
574 cpuidle_remove_state_sysfs(device);
575}
576
415/** 577/**
416 * cpuidle_add_sysfs - creates a sysfs instance for the target device 578 * cpuidle_add_sysfs - creates a sysfs instance for the target device
417 * @dev: the target device 579 * @dev: the target device
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index d08e1afa4919..3711b34dc4f9 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -91,7 +91,7 @@ struct cpuidle_device {
91 int state_count; 91 int state_count;
92 struct cpuidle_state_usage states_usage[CPUIDLE_STATE_MAX]; 92 struct cpuidle_state_usage states_usage[CPUIDLE_STATE_MAX];
93 struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX]; 93 struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX];
94 94 struct cpuidle_driver_kobj *kobj_driver;
95 struct list_head device_list; 95 struct list_head device_list;
96 struct kobject kobj; 96 struct kobject kobj;
97 struct completion kobj_unregister; 97 struct completion kobj_unregister;
@@ -157,6 +157,10 @@ extern int cpuidle_wrap_enter(struct cpuidle_device *dev,
157 struct cpuidle_driver *drv, int index)); 157 struct cpuidle_driver *drv, int index));
158extern int cpuidle_play_dead(void); 158extern int cpuidle_play_dead(void);
159 159
160extern struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev);
161extern int cpuidle_register_cpu_driver(struct cpuidle_driver *drv, int cpu);
162extern void cpuidle_unregister_cpu_driver(struct cpuidle_driver *drv, int cpu);
163
160#else 164#else
161static inline void disable_cpuidle(void) { } 165static inline void disable_cpuidle(void) { }
162static inline int cpuidle_idle_call(void) { return -ENODEV; } 166static inline int cpuidle_idle_call(void) { return -ENODEV; }
@@ -183,7 +187,6 @@ static inline int cpuidle_wrap_enter(struct cpuidle_device *dev,
183 struct cpuidle_driver *drv, int index)) 187 struct cpuidle_driver *drv, int index))
184{ return -ENODEV; } 188{ return -ENODEV; }
185static inline int cpuidle_play_dead(void) {return -ENODEV; } 189static inline int cpuidle_play_dead(void) {return -ENODEV; }
186
187#endif 190#endif
188 191
189#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED 192#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED