Branch data Line data Source code
1 : : /*
2 : : * sysfs.c - sysfs support
3 : : *
4 : : * (C) 2006-2007 Shaohua Li <shaohua.li@intel.com>
5 : : *
6 : : * This code is licenced under the GPL.
7 : : */
8 : :
9 : : #include <linux/kernel.h>
10 : : #include <linux/cpuidle.h>
11 : : #include <linux/sysfs.h>
12 : : #include <linux/slab.h>
13 : : #include <linux/cpu.h>
14 : : #include <linux/completion.h>
15 : : #include <linux/capability.h>
16 : : #include <linux/device.h>
17 : : #include <linux/kobject.h>
18 : :
19 : : #include "cpuidle.h"
20 : :
21 : : static unsigned int sysfs_switch;
22 : 0 : static int __init cpuidle_sysfs_setup(char *unused)
23 : : {
24 : 0 : sysfs_switch = 1;
25 : 0 : return 1;
26 : : }
27 : : __setup("cpuidle_sysfs_switch", cpuidle_sysfs_setup);
28 : :
29 : 0 : static ssize_t show_available_governors(struct device *dev,
30 : : struct device_attribute *attr,
31 : : char *buf)
32 : : {
33 : : ssize_t i = 0;
34 : : struct cpuidle_governor *tmp;
35 : :
36 : 0 : mutex_lock(&cpuidle_lock);
37 [ # # ]: 0 : list_for_each_entry(tmp, &cpuidle_governors, governor_list) {
38 [ # # ]: 0 : if (i >= (ssize_t) ((PAGE_SIZE/sizeof(char)) -
39 : : CPUIDLE_NAME_LEN - 2))
40 : : goto out;
41 : 0 : i += scnprintf(&buf[i], CPUIDLE_NAME_LEN, "%s ", tmp->name);
42 : : }
43 : :
44 : : out:
45 : 0 : i+= sprintf(&buf[i], "\n");
46 : 0 : mutex_unlock(&cpuidle_lock);
47 : 0 : return i;
48 : : }
49 : :
50 : 0 : static ssize_t show_current_driver(struct device *dev,
51 : : struct device_attribute *attr,
52 : : char *buf)
53 : : {
54 : : ssize_t ret;
55 : : struct cpuidle_driver *drv;
56 : :
57 : : spin_lock(&cpuidle_driver_lock);
58 : 0 : drv = cpuidle_get_driver();
59 [ # # ]: 0 : if (drv)
60 : 0 : ret = sprintf(buf, "%s\n", drv->name);
61 : : else
62 : 0 : ret = sprintf(buf, "none\n");
63 : : spin_unlock(&cpuidle_driver_lock);
64 : :
65 : 0 : return ret;
66 : : }
67 : :
68 : 0 : static ssize_t show_current_governor(struct device *dev,
69 : : struct device_attribute *attr,
70 : : char *buf)
71 : : {
72 : : ssize_t ret;
73 : :
74 : 0 : mutex_lock(&cpuidle_lock);
75 [ # # ]: 0 : if (cpuidle_curr_governor)
76 : 0 : ret = sprintf(buf, "%s\n", cpuidle_curr_governor->name);
77 : : else
78 : 0 : ret = sprintf(buf, "none\n");
79 : 0 : mutex_unlock(&cpuidle_lock);
80 : :
81 : 0 : return ret;
82 : : }
83 : :
84 : 0 : static ssize_t store_current_governor(struct device *dev,
85 : : struct device_attribute *attr,
86 : : const char *buf, size_t count)
87 : : {
88 : : char gov_name[CPUIDLE_NAME_LEN];
89 : : int ret = -EINVAL;
90 : : size_t len = count;
91 : : struct cpuidle_governor *gov;
92 : :
93 [ # # ]: 0 : if (!len || len >= sizeof(gov_name))
94 : : return -EINVAL;
95 : :
96 : 0 : memcpy(gov_name, buf, len);
97 : 0 : gov_name[len] = '\0';
98 [ # # ]: 0 : if (gov_name[len - 1] == '\n')
99 : 0 : gov_name[--len] = '\0';
100 : :
101 : 0 : mutex_lock(&cpuidle_lock);
102 : :
103 [ # # ]: 0 : list_for_each_entry(gov, &cpuidle_governors, governor_list) {
104 [ # # ][ # # ]: 0 : if (strlen(gov->name) == len && !strcmp(gov->name, gov_name)) {
105 : 0 : ret = cpuidle_switch_governor(gov);
106 : 0 : break;
107 : : }
108 : : }
109 : :
110 : 0 : mutex_unlock(&cpuidle_lock);
111 : :
112 [ # # ]: 0 : if (ret)
113 : : return ret;
114 : : else
115 : 0 : return count;
116 : : }
117 : :
118 : : static DEVICE_ATTR(current_driver, 0444, show_current_driver, NULL);
119 : : static DEVICE_ATTR(current_governor_ro, 0444, show_current_governor, NULL);
120 : :
121 : : static struct attribute *cpuidle_default_attrs[] = {
122 : : &dev_attr_current_driver.attr,
123 : : &dev_attr_current_governor_ro.attr,
124 : : NULL
125 : : };
126 : :
127 : : static DEVICE_ATTR(available_governors, 0444, show_available_governors, NULL);
128 : : static DEVICE_ATTR(current_governor, 0644, show_current_governor,
129 : : store_current_governor);
130 : :
131 : : static struct attribute *cpuidle_switch_attrs[] = {
132 : : &dev_attr_available_governors.attr,
133 : : &dev_attr_current_driver.attr,
134 : : &dev_attr_current_governor.attr,
135 : : NULL
136 : : };
137 : :
138 : : static struct attribute_group cpuidle_attr_group = {
139 : : .attrs = cpuidle_default_attrs,
140 : : .name = "cpuidle",
141 : : };
142 : :
143 : : /**
144 : : * cpuidle_add_interface - add CPU global sysfs attributes
145 : : */
146 : 0 : int cpuidle_add_interface(struct device *dev)
147 : : {
148 [ # # ]: 0 : if (sysfs_switch)
149 : 0 : cpuidle_attr_group.attrs = cpuidle_switch_attrs;
150 : :
151 : 0 : return sysfs_create_group(&dev->kobj, &cpuidle_attr_group);
152 : : }
153 : :
154 : : /**
155 : : * cpuidle_remove_interface - remove CPU global sysfs attributes
156 : : */
157 : 0 : void cpuidle_remove_interface(struct device *dev)
158 : : {
159 : 0 : sysfs_remove_group(&dev->kobj, &cpuidle_attr_group);
160 : 0 : }
161 : :
162 : : struct cpuidle_attr {
163 : : struct attribute attr;
164 : : ssize_t (*show)(struct cpuidle_device *, char *);
165 : : ssize_t (*store)(struct cpuidle_device *, const char *, size_t count);
166 : : };
167 : :
168 : : #define define_one_ro(_name, show) \
169 : : static struct cpuidle_attr attr_##_name = __ATTR(_name, 0444, show, NULL)
170 : : #define define_one_rw(_name, show, store) \
171 : : static struct cpuidle_attr attr_##_name = __ATTR(_name, 0644, show, store)
172 : :
173 : : #define attr_to_cpuidleattr(a) container_of(a, struct cpuidle_attr, attr)
174 : :
175 : : struct cpuidle_device_kobj {
176 : : struct cpuidle_device *dev;
177 : : struct completion kobj_unregister;
178 : : struct kobject kobj;
179 : : };
180 : :
181 : : static inline struct cpuidle_device *to_cpuidle_device(struct kobject *kobj)
182 : : {
183 : : struct cpuidle_device_kobj *kdev =
184 : : container_of(kobj, struct cpuidle_device_kobj, kobj);
185 : :
186 : 0 : return kdev->dev;
187 : : }
188 : :
189 : 0 : static ssize_t cpuidle_show(struct kobject *kobj, struct attribute *attr,
190 : : char *buf)
191 : : {
192 : : int ret = -EIO;
193 : : struct cpuidle_device *dev = to_cpuidle_device(kobj);
194 : : struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr);
195 : :
196 [ # # ]: 0 : if (cattr->show) {
197 : 0 : mutex_lock(&cpuidle_lock);
198 : 0 : ret = cattr->show(dev, buf);
199 : 0 : mutex_unlock(&cpuidle_lock);
200 : : }
201 : 0 : return ret;
202 : : }
203 : :
204 : 0 : static ssize_t cpuidle_store(struct kobject *kobj, struct attribute *attr,
205 : : const char *buf, size_t count)
206 : : {
207 : : int ret = -EIO;
208 : : struct cpuidle_device *dev = to_cpuidle_device(kobj);
209 : : struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr);
210 : :
211 [ # # ]: 0 : if (cattr->store) {
212 : 0 : mutex_lock(&cpuidle_lock);
213 : 0 : ret = cattr->store(dev, buf, count);
214 : 0 : mutex_unlock(&cpuidle_lock);
215 : : }
216 : 0 : return ret;
217 : : }
218 : :
219 : : static const struct sysfs_ops cpuidle_sysfs_ops = {
220 : : .show = cpuidle_show,
221 : : .store = cpuidle_store,
222 : : };
223 : :
224 : 0 : static void cpuidle_sysfs_release(struct kobject *kobj)
225 : : {
226 : : struct cpuidle_device_kobj *kdev =
227 : : container_of(kobj, struct cpuidle_device_kobj, kobj);
228 : :
229 : 0 : complete(&kdev->kobj_unregister);
230 : 0 : }
231 : :
232 : : static struct kobj_type ktype_cpuidle = {
233 : : .sysfs_ops = &cpuidle_sysfs_ops,
234 : : .release = cpuidle_sysfs_release,
235 : : };
236 : :
237 : : struct cpuidle_state_attr {
238 : : struct attribute attr;
239 : : ssize_t (*show)(struct cpuidle_state *, \
240 : : struct cpuidle_state_usage *, char *);
241 : : ssize_t (*store)(struct cpuidle_state *, \
242 : : struct cpuidle_state_usage *, const char *, size_t);
243 : : };
244 : :
245 : : #define define_one_state_ro(_name, show) \
246 : : static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL)
247 : :
248 : : #define define_one_state_rw(_name, show, store) \
249 : : static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0644, show, store)
250 : :
251 : : #define define_show_state_function(_name) \
252 : : static ssize_t show_state_##_name(struct cpuidle_state *state, \
253 : : struct cpuidle_state_usage *state_usage, char *buf) \
254 : : { \
255 : : return sprintf(buf, "%u\n", state->_name);\
256 : : }
257 : :
258 : : #define define_store_state_ull_function(_name) \
259 : : static ssize_t store_state_##_name(struct cpuidle_state *state, \
260 : : struct cpuidle_state_usage *state_usage, \
261 : : const char *buf, size_t size) \
262 : : { \
263 : : unsigned long long value; \
264 : : int err; \
265 : : if (!capable(CAP_SYS_ADMIN)) \
266 : : return -EPERM; \
267 : : err = kstrtoull(buf, 0, &value); \
268 : : if (err) \
269 : : return err; \
270 : : if (value) \
271 : : state_usage->_name = 1; \
272 : : else \
273 : : state_usage->_name = 0; \
274 : : return size; \
275 : : }
276 : :
277 : : #define define_show_state_ull_function(_name) \
278 : : static ssize_t show_state_##_name(struct cpuidle_state *state, \
279 : : struct cpuidle_state_usage *state_usage, \
280 : : char *buf) \
281 : : { \
282 : : return sprintf(buf, "%llu\n", state_usage->_name);\
283 : : }
284 : :
285 : : #define define_show_state_str_function(_name) \
286 : : static ssize_t show_state_##_name(struct cpuidle_state *state, \
287 : : struct cpuidle_state_usage *state_usage, \
288 : : char *buf) \
289 : : { \
290 : : if (state->_name[0] == '\0')\
291 : : return sprintf(buf, "<null>\n");\
292 : : return sprintf(buf, "%s\n", state->_name);\
293 : : }
294 : :
295 : 0 : define_show_state_function(exit_latency)
296 : 0 : define_show_state_function(power_usage)
297 : 0 : define_show_state_ull_function(usage)
298 : 0 : define_show_state_ull_function(time)
299 [ # # ]: 0 : define_show_state_str_function(name)
300 [ # # ]: 0 : define_show_state_str_function(desc)
301 : 0 : define_show_state_ull_function(disable)
302 [ # # ][ # # ]: 0 : define_store_state_ull_function(disable)
[ # # ]
303 : :
304 : : define_one_state_ro(name, show_state_name);
305 : : define_one_state_ro(desc, show_state_desc);
306 : : define_one_state_ro(latency, show_state_exit_latency);
307 : : define_one_state_ro(power, show_state_power_usage);
308 : : define_one_state_ro(usage, show_state_usage);
309 : : define_one_state_ro(time, show_state_time);
310 : : define_one_state_rw(disable, show_state_disable, store_state_disable);
311 : :
312 : : static struct attribute *cpuidle_state_default_attrs[] = {
313 : : &attr_name.attr,
314 : : &attr_desc.attr,
315 : : &attr_latency.attr,
316 : : &attr_power.attr,
317 : : &attr_usage.attr,
318 : : &attr_time.attr,
319 : : &attr_disable.attr,
320 : : NULL
321 : : };
322 : :
323 : : struct cpuidle_state_kobj {
324 : : struct cpuidle_state *state;
325 : : struct cpuidle_state_usage *state_usage;
326 : : struct completion kobj_unregister;
327 : : struct kobject kobj;
328 : : };
329 : :
330 : : #define kobj_to_state_obj(k) container_of(k, struct cpuidle_state_kobj, kobj)
331 : : #define kobj_to_state(k) (kobj_to_state_obj(k)->state)
332 : : #define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage)
333 : : #define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr)
334 : :
335 : 0 : static ssize_t cpuidle_state_show(struct kobject *kobj, struct attribute *attr,
336 : : char * buf)
337 : : {
338 : : int ret = -EIO;
339 : 0 : struct cpuidle_state *state = kobj_to_state(kobj);
340 : 0 : struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj);
341 : : struct cpuidle_state_attr * cattr = attr_to_stateattr(attr);
342 : :
343 [ # # ]: 0 : if (cattr->show)
344 : 0 : ret = cattr->show(state, state_usage, buf);
345 : :
346 : 0 : return ret;
347 : : }
348 : :
349 : 0 : static ssize_t cpuidle_state_store(struct kobject *kobj, struct attribute *attr,
350 : : const char *buf, size_t size)
351 : : {
352 : : int ret = -EIO;
353 : 0 : struct cpuidle_state *state = kobj_to_state(kobj);
354 : 0 : struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj);
355 : : struct cpuidle_state_attr *cattr = attr_to_stateattr(attr);
356 : :
357 [ # # ]: 0 : if (cattr->store)
358 : 0 : ret = cattr->store(state, state_usage, buf, size);
359 : :
360 : 0 : return ret;
361 : : }
362 : :
363 : : static const struct sysfs_ops cpuidle_state_sysfs_ops = {
364 : : .show = cpuidle_state_show,
365 : : .store = cpuidle_state_store,
366 : : };
367 : :
368 : 0 : static void cpuidle_state_sysfs_release(struct kobject *kobj)
369 : : {
370 : : struct cpuidle_state_kobj *state_obj = kobj_to_state_obj(kobj);
371 : :
372 : 0 : complete(&state_obj->kobj_unregister);
373 : 0 : }
374 : :
375 : : static struct kobj_type ktype_state_cpuidle = {
376 : : .sysfs_ops = &cpuidle_state_sysfs_ops,
377 : : .default_attrs = cpuidle_state_default_attrs,
378 : : .release = cpuidle_state_sysfs_release,
379 : : };
380 : :
381 : : static inline void cpuidle_free_state_kobj(struct cpuidle_device *device, int i)
382 : : {
383 : 0 : kobject_put(&device->kobjs[i]->kobj);
384 : 0 : wait_for_completion(&device->kobjs[i]->kobj_unregister);
385 : 0 : kfree(device->kobjs[i]);
386 : 0 : device->kobjs[i] = NULL;
387 : : }
388 : :
389 : : /**
390 : : * cpuidle_add_state_sysfs - adds cpuidle states sysfs attributes
391 : : * @device: the target device
392 : : */
393 : 0 : static int cpuidle_add_state_sysfs(struct cpuidle_device *device)
394 : : {
395 : : int i, ret = -ENOMEM;
396 : : struct cpuidle_state_kobj *kobj;
397 : 0 : struct cpuidle_device_kobj *kdev = device->kobj_dev;
398 : 0 : struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device);
399 : :
400 : : /* state statistics */
401 [ # # ]: 0 : for (i = 0; i < device->state_count; i++) {
402 : : kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL);
403 [ # # ]: 0 : if (!kobj)
404 : : goto error_state;
405 : 0 : kobj->state = &drv->states[i];
406 : 0 : kobj->state_usage = &device->states_usage[i];
407 : : init_completion(&kobj->kobj_unregister);
408 : :
409 : 0 : ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle,
410 : : &kdev->kobj, "state%d", i);
411 [ # # ]: 0 : if (ret) {
412 : 0 : kfree(kobj);
413 : 0 : goto error_state;
414 : : }
415 : 0 : kobject_uevent(&kobj->kobj, KOBJ_ADD);
416 : 0 : device->kobjs[i] = kobj;
417 : : }
418 : :
419 : : return 0;
420 : :
421 : : error_state:
422 [ # # ]: 0 : for (i = i - 1; i >= 0; i--)
423 : : cpuidle_free_state_kobj(device, i);
424 : : return ret;
425 : : }
426 : :
427 : : /**
428 : : * cpuidle_remove_driver_sysfs - removes the cpuidle states sysfs attributes
429 : : * @device: the target device
430 : : */
431 : 0 : static void cpuidle_remove_state_sysfs(struct cpuidle_device *device)
432 : : {
433 : : int i;
434 : :
435 [ # # ]: 0 : for (i = 0; i < device->state_count; i++)
436 : : cpuidle_free_state_kobj(device, i);
437 : 0 : }
438 : :
439 : : #ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS
440 : : #define kobj_to_driver_kobj(k) container_of(k, struct cpuidle_driver_kobj, kobj)
441 : : #define attr_to_driver_attr(a) container_of(a, struct cpuidle_driver_attr, attr)
442 : :
443 : : #define define_one_driver_ro(_name, show) \
444 : : static struct cpuidle_driver_attr attr_driver_##_name = \
445 : : __ATTR(_name, 0644, show, NULL)
446 : :
447 : : struct cpuidle_driver_kobj {
448 : : struct cpuidle_driver *drv;
449 : : struct completion kobj_unregister;
450 : : struct kobject kobj;
451 : : };
452 : :
453 : : struct cpuidle_driver_attr {
454 : : struct attribute attr;
455 : : ssize_t (*show)(struct cpuidle_driver *, char *);
456 : : ssize_t (*store)(struct cpuidle_driver *, const char *, size_t);
457 : : };
458 : :
459 : 0 : static ssize_t show_driver_name(struct cpuidle_driver *drv, char *buf)
460 : : {
461 : : ssize_t ret;
462 : :
463 : : spin_lock(&cpuidle_driver_lock);
464 [ # # ]: 0 : ret = sprintf(buf, "%s\n", drv ? drv->name : "none");
465 : : spin_unlock(&cpuidle_driver_lock);
466 : :
467 : 0 : return ret;
468 : : }
469 : :
470 : 0 : static void cpuidle_driver_sysfs_release(struct kobject *kobj)
471 : : {
472 : : struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj);
473 : 0 : complete(&driver_kobj->kobj_unregister);
474 : 0 : }
475 : :
476 : 0 : static ssize_t cpuidle_driver_show(struct kobject *kobj, struct attribute *attr,
477 : : char *buf)
478 : : {
479 : : int ret = -EIO;
480 : : struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj);
481 : : struct cpuidle_driver_attr *dattr = attr_to_driver_attr(attr);
482 : :
483 [ # # ]: 0 : if (dattr->show)
484 : 0 : ret = dattr->show(driver_kobj->drv, buf);
485 : :
486 : 0 : return ret;
487 : : }
488 : :
489 : 0 : static ssize_t cpuidle_driver_store(struct kobject *kobj, struct attribute *attr,
490 : : const char *buf, size_t size)
491 : : {
492 : : int ret = -EIO;
493 : : struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj);
494 : : struct cpuidle_driver_attr *dattr = attr_to_driver_attr(attr);
495 : :
496 [ # # ]: 0 : if (dattr->store)
497 : 0 : ret = dattr->store(driver_kobj->drv, buf, size);
498 : :
499 : 0 : return ret;
500 : : }
501 : :
502 : : define_one_driver_ro(name, show_driver_name);
503 : :
504 : : static const struct sysfs_ops cpuidle_driver_sysfs_ops = {
505 : : .show = cpuidle_driver_show,
506 : : .store = cpuidle_driver_store,
507 : : };
508 : :
509 : : static struct attribute *cpuidle_driver_default_attrs[] = {
510 : : &attr_driver_name.attr,
511 : : NULL
512 : : };
513 : :
514 : : static struct kobj_type ktype_driver_cpuidle = {
515 : : .sysfs_ops = &cpuidle_driver_sysfs_ops,
516 : : .default_attrs = cpuidle_driver_default_attrs,
517 : : .release = cpuidle_driver_sysfs_release,
518 : : };
519 : :
520 : : /**
521 : : * cpuidle_add_driver_sysfs - adds the driver name sysfs attribute
522 : : * @device: the target device
523 : : */
524 : 0 : static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev)
525 : : {
526 : : struct cpuidle_driver_kobj *kdrv;
527 : 0 : struct cpuidle_device_kobj *kdev = dev->kobj_dev;
528 : 0 : struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
529 : : int ret;
530 : :
531 : : kdrv = kzalloc(sizeof(*kdrv), GFP_KERNEL);
532 [ # # ]: 0 : if (!kdrv)
533 : : return -ENOMEM;
534 : :
535 : 0 : kdrv->drv = drv;
536 : : init_completion(&kdrv->kobj_unregister);
537 : :
538 : 0 : ret = kobject_init_and_add(&kdrv->kobj, &ktype_driver_cpuidle,
539 : : &kdev->kobj, "driver");
540 [ # # ]: 0 : if (ret) {
541 : 0 : kfree(kdrv);
542 : 0 : return ret;
543 : : }
544 : :
545 : 0 : kobject_uevent(&kdrv->kobj, KOBJ_ADD);
546 : 0 : dev->kobj_driver = kdrv;
547 : :
548 : 0 : return ret;
549 : : }
550 : :
551 : : /**
552 : : * cpuidle_remove_driver_sysfs - removes the driver name sysfs attribute
553 : : * @device: the target device
554 : : */
555 : 0 : static void cpuidle_remove_driver_sysfs(struct cpuidle_device *dev)
556 : : {
557 : 0 : struct cpuidle_driver_kobj *kdrv = dev->kobj_driver;
558 : 0 : kobject_put(&kdrv->kobj);
559 : 0 : wait_for_completion(&kdrv->kobj_unregister);
560 : 0 : kfree(kdrv);
561 : 0 : }
562 : : #else
563 : : static inline int cpuidle_add_driver_sysfs(struct cpuidle_device *dev)
564 : : {
565 : : return 0;
566 : : }
567 : :
568 : : static inline void cpuidle_remove_driver_sysfs(struct cpuidle_device *dev)
569 : : {
570 : : ;
571 : : }
572 : : #endif
573 : :
574 : : /**
575 : : * cpuidle_add_device_sysfs - adds device specific sysfs attributes
576 : : * @device: the target device
577 : : */
578 : 0 : int cpuidle_add_device_sysfs(struct cpuidle_device *device)
579 : : {
580 : : int ret;
581 : :
582 : 0 : ret = cpuidle_add_state_sysfs(device);
583 [ # # ]: 0 : if (ret)
584 : : return ret;
585 : :
586 : 0 : ret = cpuidle_add_driver_sysfs(device);
587 [ # # ]: 0 : if (ret)
588 : 0 : cpuidle_remove_state_sysfs(device);
589 : 0 : return ret;
590 : : }
591 : :
592 : : /**
593 : : * cpuidle_remove_device_sysfs : removes device specific sysfs attributes
594 : : * @device : the target device
595 : : */
596 : 0 : void cpuidle_remove_device_sysfs(struct cpuidle_device *device)
597 : : {
598 : 0 : cpuidle_remove_driver_sysfs(device);
599 : 0 : cpuidle_remove_state_sysfs(device);
600 : 0 : }
601 : :
602 : : /**
603 : : * cpuidle_add_sysfs - creates a sysfs instance for the target device
604 : : * @dev: the target device
605 : : */
606 : 0 : int cpuidle_add_sysfs(struct cpuidle_device *dev)
607 : : {
608 : : struct cpuidle_device_kobj *kdev;
609 : 0 : struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu);
610 : : int error;
611 : :
612 : : kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
613 [ # # ]: 0 : if (!kdev)
614 : : return -ENOMEM;
615 : 0 : kdev->dev = dev;
616 : 0 : dev->kobj_dev = kdev;
617 : :
618 : : init_completion(&kdev->kobj_unregister);
619 : :
620 : 0 : error = kobject_init_and_add(&kdev->kobj, &ktype_cpuidle, &cpu_dev->kobj,
621 : : "cpuidle");
622 [ # # ]: 0 : if (error) {
623 : 0 : kfree(kdev);
624 : 0 : return error;
625 : : }
626 : :
627 : 0 : kobject_uevent(&kdev->kobj, KOBJ_ADD);
628 : :
629 : 0 : return 0;
630 : : }
631 : :
632 : : /**
633 : : * cpuidle_remove_sysfs - deletes a sysfs instance on the target device
634 : : * @dev: the target device
635 : : */
636 : 0 : void cpuidle_remove_sysfs(struct cpuidle_device *dev)
637 : : {
638 : 0 : struct cpuidle_device_kobj *kdev = dev->kobj_dev;
639 : :
640 : 0 : kobject_put(&kdev->kobj);
641 : 0 : wait_for_completion(&kdev->kobj_unregister);
642 : 0 : kfree(kdev);
643 : 0 : }
|