]> git.ipfire.org Git - people/ms/linux.git/blame - drivers/powercap/powercap_sys.c
Importing "grsecurity-3.1-3.19.2-201503201903.patch"
[people/ms/linux.git] / drivers / powercap / powercap_sys.c
CommitLineData
75d2364e
SP
1/*
2 * Power capping class
3 * Copyright (c) 2013, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.
16 *
17 */
18
19#include <linux/module.h>
20#include <linux/device.h>
21#include <linux/err.h>
22#include <linux/slab.h>
23#include <linux/powercap.h>
24
25#define to_powercap_zone(n) container_of(n, struct powercap_zone, dev)
26#define to_powercap_control_type(n) \
27 container_of(n, struct powercap_control_type, dev)
28
29/* Power zone show function */
30#define define_power_zone_show(_attr) \
31static ssize_t _attr##_show(struct device *dev, \
32 struct device_attribute *dev_attr,\
33 char *buf) \
34{ \
35 u64 value; \
36 ssize_t len = -EINVAL; \
37 struct powercap_zone *power_zone = to_powercap_zone(dev); \
38 \
39 if (power_zone->ops->get_##_attr) { \
40 if (!power_zone->ops->get_##_attr(power_zone, &value)) \
41 len = sprintf(buf, "%lld\n", value); \
42 } \
43 \
44 return len; \
45}
46
47/* The only meaningful input is 0 (reset), others are silently ignored */
48#define define_power_zone_store(_attr) \
49static ssize_t _attr##_store(struct device *dev,\
50 struct device_attribute *dev_attr, \
51 const char *buf, size_t count) \
52{ \
53 int err; \
54 struct powercap_zone *power_zone = to_powercap_zone(dev); \
55 u64 value; \
56 \
57 err = kstrtoull(buf, 10, &value); \
58 if (err) \
59 return -EINVAL; \
60 if (value) \
61 return count; \
62 if (power_zone->ops->reset_##_attr) { \
63 if (!power_zone->ops->reset_##_attr(power_zone)) \
64 return count; \
65 } \
66 \
67 return -EINVAL; \
68}
69
70/* Power zone constraint show function */
71#define define_power_zone_constraint_show(_attr) \
72static ssize_t show_constraint_##_attr(struct device *dev, \
73 struct device_attribute *dev_attr,\
74 char *buf) \
75{ \
76 u64 value; \
77 ssize_t len = -ENODATA; \
78 struct powercap_zone *power_zone = to_powercap_zone(dev); \
79 int id; \
80 struct powercap_zone_constraint *pconst;\
81 \
82 if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \
83 return -EINVAL; \
84 if (id >= power_zone->const_id_cnt) \
85 return -EINVAL; \
86 pconst = &power_zone->constraints[id]; \
87 if (pconst && pconst->ops && pconst->ops->get_##_attr) { \
88 if (!pconst->ops->get_##_attr(power_zone, id, &value)) \
89 len = sprintf(buf, "%lld\n", value); \
90 } \
91 \
92 return len; \
93}
94
95/* Power zone constraint store function */
96#define define_power_zone_constraint_store(_attr) \
97static ssize_t store_constraint_##_attr(struct device *dev,\
98 struct device_attribute *dev_attr, \
99 const char *buf, size_t count) \
100{ \
101 int err; \
102 u64 value; \
103 struct powercap_zone *power_zone = to_powercap_zone(dev); \
104 int id; \
105 struct powercap_zone_constraint *pconst;\
106 \
107 if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \
108 return -EINVAL; \
109 if (id >= power_zone->const_id_cnt) \
110 return -EINVAL; \
111 pconst = &power_zone->constraints[id]; \
112 err = kstrtoull(buf, 10, &value); \
113 if (err) \
114 return -EINVAL; \
115 if (pconst && pconst->ops && pconst->ops->set_##_attr) { \
116 if (!pconst->ops->set_##_attr(power_zone, id, value)) \
117 return count; \
118 } \
119 \
120 return -ENODATA; \
121}
122
123/* Power zone information callbacks */
124define_power_zone_show(power_uw);
125define_power_zone_show(max_power_range_uw);
126define_power_zone_show(energy_uj);
127define_power_zone_store(energy_uj);
128define_power_zone_show(max_energy_range_uj);
129
130/* Power zone attributes */
131static DEVICE_ATTR_RO(max_power_range_uw);
132static DEVICE_ATTR_RO(power_uw);
133static DEVICE_ATTR_RO(max_energy_range_uj);
134static DEVICE_ATTR_RW(energy_uj);
135
136/* Power zone constraint attributes callbacks */
137define_power_zone_constraint_show(power_limit_uw);
138define_power_zone_constraint_store(power_limit_uw);
139define_power_zone_constraint_show(time_window_us);
140define_power_zone_constraint_store(time_window_us);
141define_power_zone_constraint_show(max_power_uw);
142define_power_zone_constraint_show(min_power_uw);
143define_power_zone_constraint_show(max_time_window_us);
144define_power_zone_constraint_show(min_time_window_us);
145
146/* For one time seeding of constraint device attributes */
147struct powercap_constraint_attr {
148 struct device_attribute power_limit_attr;
149 struct device_attribute time_window_attr;
150 struct device_attribute max_power_attr;
151 struct device_attribute min_power_attr;
152 struct device_attribute max_time_window_attr;
153 struct device_attribute min_time_window_attr;
154 struct device_attribute name_attr;
155};
156
63d9c273
MT
157static ssize_t show_constraint_name(struct device *dev,
158 struct device_attribute *dev_attr,
159 char *buf);
160
75d2364e 161static struct powercap_constraint_attr
63d9c273
MT
162 constraint_attrs[MAX_CONSTRAINTS_PER_ZONE] = {
163 [0 ... MAX_CONSTRAINTS_PER_ZONE - 1] = {
164 .power_limit_attr = {
165 .attr = {
166 .name = NULL,
167 .mode = S_IWUSR | S_IRUGO
168 },
169 .show = show_constraint_power_limit_uw,
170 .store = store_constraint_power_limit_uw
171 },
172
173 .time_window_attr = {
174 .attr = {
175 .name = NULL,
176 .mode = S_IWUSR | S_IRUGO
177 },
178 .show = show_constraint_time_window_us,
179 .store = store_constraint_time_window_us
180 },
181
182 .max_power_attr = {
183 .attr = {
184 .name = NULL,
185 .mode = S_IRUGO
186 },
187 .show = show_constraint_max_power_uw,
188 .store = NULL
189 },
190
191 .min_power_attr = {
192 .attr = {
193 .name = NULL,
194 .mode = S_IRUGO
195 },
196 .show = show_constraint_min_power_uw,
197 .store = NULL
198 },
199
200 .max_time_window_attr = {
201 .attr = {
202 .name = NULL,
203 .mode = S_IRUGO
204 },
205 .show = show_constraint_max_time_window_us,
206 .store = NULL
207 },
208
209 .min_time_window_attr = {
210 .attr = {
211 .name = NULL,
212 .mode = S_IRUGO
213 },
214 .show = show_constraint_min_time_window_us,
215 .store = NULL
216 },
217
218 .name_attr = {
219 .attr = {
220 .name = NULL,
221 .mode = S_IRUGO
222 },
223 .show = show_constraint_name,
224 .store = NULL
225 }
226 }
227};
75d2364e
SP
228
229/* A list of powercap control_types */
230static LIST_HEAD(powercap_cntrl_list);
231/* Mutex to protect list of powercap control_types */
232static DEFINE_MUTEX(powercap_cntrl_list_lock);
233
234#define POWERCAP_CONSTRAINT_NAME_LEN 30 /* Some limit to avoid overflow */
235static ssize_t show_constraint_name(struct device *dev,
236 struct device_attribute *dev_attr,
237 char *buf)
238{
239 const char *name;
240 struct powercap_zone *power_zone = to_powercap_zone(dev);
241 int id;
242 ssize_t len = -ENODATA;
243 struct powercap_zone_constraint *pconst;
244
245 if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id))
246 return -EINVAL;
247 if (id >= power_zone->const_id_cnt)
248 return -EINVAL;
249 pconst = &power_zone->constraints[id];
250
251 if (pconst && pconst->ops && pconst->ops->get_name) {
252 name = pconst->ops->get_name(power_zone, id);
253 if (name) {
254 snprintf(buf, POWERCAP_CONSTRAINT_NAME_LEN,
255 "%s\n", name);
256 buf[POWERCAP_CONSTRAINT_NAME_LEN] = '\0';
257 len = strlen(buf);
258 }
259 }
260
261 return len;
262}
263
264static int create_constraint_attribute(int id, const char *name,
63d9c273 265 struct device_attribute *dev_attr)
75d2364e 266{
63d9c273 267 name = kasprintf(GFP_KERNEL, "constraint_%d_%s", id, name);
75d2364e 268
63d9c273 269 if (!name)
75d2364e 270 return -ENOMEM;
63d9c273
MT
271
272 pax_open_kernel();
273 *(const char **)&dev_attr->attr.name = name;
274 pax_close_kernel();
75d2364e
SP
275
276 return 0;
277}
278
279static void free_constraint_attributes(void)
280{
281 int i;
282
283 for (i = 0; i < MAX_CONSTRAINTS_PER_ZONE; ++i) {
284 kfree(constraint_attrs[i].power_limit_attr.attr.name);
285 kfree(constraint_attrs[i].time_window_attr.attr.name);
286 kfree(constraint_attrs[i].name_attr.attr.name);
287 kfree(constraint_attrs[i].max_power_attr.attr.name);
288 kfree(constraint_attrs[i].min_power_attr.attr.name);
289 kfree(constraint_attrs[i].max_time_window_attr.attr.name);
290 kfree(constraint_attrs[i].min_time_window_attr.attr.name);
291 }
292}
293
294static int seed_constraint_attributes(void)
295{
296 int i;
297 int ret;
298
299 for (i = 0; i < MAX_CONSTRAINTS_PER_ZONE; ++i) {
300 ret = create_constraint_attribute(i, "power_limit_uw",
63d9c273 301 &constraint_attrs[i].power_limit_attr);
75d2364e
SP
302 if (ret)
303 goto err_alloc;
304 ret = create_constraint_attribute(i, "time_window_us",
63d9c273 305 &constraint_attrs[i].time_window_attr);
75d2364e
SP
306 if (ret)
307 goto err_alloc;
63d9c273
MT
308 ret = create_constraint_attribute(i, "name",
309 &constraint_attrs[i].name_attr);
75d2364e
SP
310 if (ret)
311 goto err_alloc;
63d9c273
MT
312 ret = create_constraint_attribute(i, "max_power_uw",
313 &constraint_attrs[i].max_power_attr);
75d2364e
SP
314 if (ret)
315 goto err_alloc;
63d9c273
MT
316 ret = create_constraint_attribute(i, "min_power_uw",
317 &constraint_attrs[i].min_power_attr);
75d2364e
SP
318 if (ret)
319 goto err_alloc;
320 ret = create_constraint_attribute(i, "max_time_window_us",
63d9c273 321 &constraint_attrs[i].max_time_window_attr);
75d2364e
SP
322 if (ret)
323 goto err_alloc;
324 ret = create_constraint_attribute(i, "min_time_window_us",
63d9c273 325 &constraint_attrs[i].min_time_window_attr);
75d2364e
SP
326 if (ret)
327 goto err_alloc;
328
329 }
330
331 return 0;
332
333err_alloc:
334 free_constraint_attributes();
335
336 return ret;
337}
338
339static int create_constraints(struct powercap_zone *power_zone,
340 int nr_constraints,
341 struct powercap_zone_constraint_ops *const_ops)
342{
343 int i;
344 int ret = 0;
345 int count;
346 struct powercap_zone_constraint *pconst;
347
348 if (!power_zone || !const_ops || !const_ops->get_power_limit_uw ||
349 !const_ops->set_power_limit_uw ||
350 !const_ops->get_time_window_us ||
351 !const_ops->set_time_window_us)
352 return -EINVAL;
353
354 count = power_zone->zone_attr_count;
355 for (i = 0; i < nr_constraints; ++i) {
356 pconst = &power_zone->constraints[i];
357 pconst->ops = const_ops;
358 pconst->id = power_zone->const_id_cnt;
359 power_zone->const_id_cnt++;
360 power_zone->zone_dev_attrs[count++] =
361 &constraint_attrs[i].power_limit_attr.attr;
362 power_zone->zone_dev_attrs[count++] =
363 &constraint_attrs[i].time_window_attr.attr;
364 if (pconst->ops->get_name)
365 power_zone->zone_dev_attrs[count++] =
366 &constraint_attrs[i].name_attr.attr;
367 if (pconst->ops->get_max_power_uw)
368 power_zone->zone_dev_attrs[count++] =
369 &constraint_attrs[i].max_power_attr.attr;
370 if (pconst->ops->get_min_power_uw)
371 power_zone->zone_dev_attrs[count++] =
372 &constraint_attrs[i].min_power_attr.attr;
373 if (pconst->ops->get_max_time_window_us)
374 power_zone->zone_dev_attrs[count++] =
375 &constraint_attrs[i].max_time_window_attr.attr;
376 if (pconst->ops->get_min_time_window_us)
377 power_zone->zone_dev_attrs[count++] =
378 &constraint_attrs[i].min_time_window_attr.attr;
379 }
380 power_zone->zone_attr_count = count;
381
382 return ret;
383}
384
385static bool control_type_valid(void *control_type)
386{
387 struct powercap_control_type *pos = NULL;
388 bool found = false;
389
390 mutex_lock(&powercap_cntrl_list_lock);
391
392 list_for_each_entry(pos, &powercap_cntrl_list, node) {
393 if (pos == control_type) {
394 found = true;
395 break;
396 }
397 }
398 mutex_unlock(&powercap_cntrl_list_lock);
399
400 return found;
401}
402
403static ssize_t name_show(struct device *dev,
404 struct device_attribute *attr,
405 char *buf)
406{
407 struct powercap_zone *power_zone = to_powercap_zone(dev);
408
409 return sprintf(buf, "%s\n", power_zone->name);
410}
411
412static DEVICE_ATTR_RO(name);
413
414/* Create zone and attributes in sysfs */
415static void create_power_zone_common_attributes(
416 struct powercap_zone *power_zone)
417{
418 int count = 0;
419
420 power_zone->zone_dev_attrs[count++] = &dev_attr_name.attr;
421 if (power_zone->ops->get_max_energy_range_uj)
422 power_zone->zone_dev_attrs[count++] =
423 &dev_attr_max_energy_range_uj.attr;
95677a9a 424 if (power_zone->ops->get_energy_uj) {
63d9c273 425 pax_open_kernel();
95677a9a 426 if (power_zone->ops->reset_energy_uj)
63d9c273 427 *(umode_t *)&dev_attr_energy_uj.attr.mode = S_IWUSR | S_IRUGO;
95677a9a 428 else
63d9c273
MT
429 *(umode_t *)&dev_attr_energy_uj.attr.mode = S_IRUGO;
430 pax_close_kernel();
75d2364e
SP
431 power_zone->zone_dev_attrs[count++] =
432 &dev_attr_energy_uj.attr;
95677a9a 433 }
75d2364e
SP
434 if (power_zone->ops->get_power_uw)
435 power_zone->zone_dev_attrs[count++] =
436 &dev_attr_power_uw.attr;
437 if (power_zone->ops->get_max_power_range_uw)
438 power_zone->zone_dev_attrs[count++] =
439 &dev_attr_max_power_range_uw.attr;
440 power_zone->zone_dev_attrs[count] = NULL;
441 power_zone->zone_attr_count = count;
442}
443
444static void powercap_release(struct device *dev)
445{
446 bool allocated;
447
448 if (dev->parent) {
449 struct powercap_zone *power_zone = to_powercap_zone(dev);
450
451 /* Store flag as the release() may free memory */
452 allocated = power_zone->allocated;
453 /* Remove id from parent idr struct */
454 idr_remove(power_zone->parent_idr, power_zone->id);
455 /* Destroy idrs allocated for this zone */
456 idr_destroy(&power_zone->idr);
457 kfree(power_zone->name);
458 kfree(power_zone->zone_dev_attrs);
459 kfree(power_zone->constraints);
460 if (power_zone->ops->release)
461 power_zone->ops->release(power_zone);
462 if (allocated)
463 kfree(power_zone);
464 } else {
465 struct powercap_control_type *control_type =
466 to_powercap_control_type(dev);
467
468 /* Store flag as the release() may free memory */
469 allocated = control_type->allocated;
470 idr_destroy(&control_type->idr);
471 mutex_destroy(&control_type->lock);
472 if (control_type->ops && control_type->ops->release)
473 control_type->ops->release(control_type);
474 if (allocated)
475 kfree(control_type);
476 }
477}
478
479static ssize_t enabled_show(struct device *dev,
480 struct device_attribute *attr,
481 char *buf)
482{
483 bool mode = true;
484
485 /* Default is enabled */
486 if (dev->parent) {
487 struct powercap_zone *power_zone = to_powercap_zone(dev);
488 if (power_zone->ops->get_enable)
489 if (power_zone->ops->get_enable(power_zone, &mode))
490 mode = false;
491 } else {
492 struct powercap_control_type *control_type =
493 to_powercap_control_type(dev);
494 if (control_type->ops && control_type->ops->get_enable)
495 if (control_type->ops->get_enable(control_type, &mode))
496 mode = false;
497 }
498
499 return sprintf(buf, "%d\n", mode);
500}
501
502static ssize_t enabled_store(struct device *dev,
503 struct device_attribute *attr,
504 const char *buf, size_t len)
505{
506 bool mode;
507
508 if (strtobool(buf, &mode))
509 return -EINVAL;
510 if (dev->parent) {
511 struct powercap_zone *power_zone = to_powercap_zone(dev);
512 if (power_zone->ops->set_enable)
513 if (!power_zone->ops->set_enable(power_zone, mode))
514 return len;
515 } else {
516 struct powercap_control_type *control_type =
517 to_powercap_control_type(dev);
518 if (control_type->ops && control_type->ops->set_enable)
519 if (!control_type->ops->set_enable(control_type, mode))
520 return len;
521 }
522
523 return -ENOSYS;
524}
525
9e3410b7
TR
526static DEVICE_ATTR_RW(enabled);
527
528static struct attribute *powercap_attrs[] = {
529 &dev_attr_enabled.attr,
530 NULL,
75d2364e 531};
9e3410b7 532ATTRIBUTE_GROUPS(powercap);
75d2364e
SP
533
534static struct class powercap_class = {
535 .name = "powercap",
536 .dev_release = powercap_release,
9e3410b7 537 .dev_groups = powercap_groups,
75d2364e
SP
538};
539
540struct powercap_zone *powercap_register_zone(
541 struct powercap_zone *power_zone,
542 struct powercap_control_type *control_type,
543 const char *name,
544 struct powercap_zone *parent,
545 const struct powercap_zone_ops *ops,
546 int nr_constraints,
547 struct powercap_zone_constraint_ops *const_ops)
548{
549 int result;
550 int nr_attrs;
551
552 if (!name || !control_type || !ops ||
553 nr_constraints > MAX_CONSTRAINTS_PER_ZONE ||
554 (!ops->get_energy_uj && !ops->get_power_uw) ||
555 !control_type_valid(control_type))
556 return ERR_PTR(-EINVAL);
557
558 if (power_zone) {
559 if (!ops->release)
560 return ERR_PTR(-EINVAL);
561 memset(power_zone, 0, sizeof(*power_zone));
562 } else {
563 power_zone = kzalloc(sizeof(*power_zone), GFP_KERNEL);
564 if (!power_zone)
565 return ERR_PTR(-ENOMEM);
566 power_zone->allocated = true;
567 }
568 power_zone->ops = ops;
569 power_zone->control_type_inst = control_type;
570 if (!parent) {
571 power_zone->dev.parent = &control_type->dev;
572 power_zone->parent_idr = &control_type->idr;
573 } else {
574 power_zone->dev.parent = &parent->dev;
575 power_zone->parent_idr = &parent->idr;
576 }
577 power_zone->dev.class = &powercap_class;
578
579 mutex_lock(&control_type->lock);
580 /* Using idr to get the unique id */
581 result = idr_alloc(power_zone->parent_idr, NULL, 0, 0, GFP_KERNEL);
582 if (result < 0)
583 goto err_idr_alloc;
584
585 power_zone->id = result;
586 idr_init(&power_zone->idr);
587 power_zone->name = kstrdup(name, GFP_KERNEL);
588 if (!power_zone->name)
589 goto err_name_alloc;
590 dev_set_name(&power_zone->dev, "%s:%x",
591 dev_name(power_zone->dev.parent),
592 power_zone->id);
593 power_zone->constraints = kzalloc(sizeof(*power_zone->constraints) *
594 nr_constraints, GFP_KERNEL);
595 if (!power_zone->constraints)
596 goto err_const_alloc;
597
598 nr_attrs = nr_constraints * POWERCAP_CONSTRAINTS_ATTRS +
599 POWERCAP_ZONE_MAX_ATTRS + 1;
600 power_zone->zone_dev_attrs = kzalloc(sizeof(void *) *
601 nr_attrs, GFP_KERNEL);
602 if (!power_zone->zone_dev_attrs)
603 goto err_attr_alloc;
604 create_power_zone_common_attributes(power_zone);
605 result = create_constraints(power_zone, nr_constraints, const_ops);
606 if (result)
607 goto err_dev_ret;
608
609 power_zone->zone_dev_attrs[power_zone->zone_attr_count] = NULL;
610 power_zone->dev_zone_attr_group.attrs = power_zone->zone_dev_attrs;
611 power_zone->dev_attr_groups[0] = &power_zone->dev_zone_attr_group;
612 power_zone->dev_attr_groups[1] = NULL;
613 power_zone->dev.groups = power_zone->dev_attr_groups;
614 result = device_register(&power_zone->dev);
615 if (result)
616 goto err_dev_ret;
617
618 control_type->nr_zones++;
619 mutex_unlock(&control_type->lock);
620
621 return power_zone;
622
623err_dev_ret:
624 kfree(power_zone->zone_dev_attrs);
625err_attr_alloc:
626 kfree(power_zone->constraints);
627err_const_alloc:
628 kfree(power_zone->name);
629err_name_alloc:
630 idr_remove(power_zone->parent_idr, power_zone->id);
631err_idr_alloc:
632 if (power_zone->allocated)
633 kfree(power_zone);
634 mutex_unlock(&control_type->lock);
635
636 return ERR_PTR(result);
637}
638EXPORT_SYMBOL_GPL(powercap_register_zone);
639
640int powercap_unregister_zone(struct powercap_control_type *control_type,
641 struct powercap_zone *power_zone)
642{
643 if (!power_zone || !control_type)
644 return -EINVAL;
645
646 mutex_lock(&control_type->lock);
647 control_type->nr_zones--;
648 mutex_unlock(&control_type->lock);
649
650 device_unregister(&power_zone->dev);
651
652 return 0;
653}
654EXPORT_SYMBOL_GPL(powercap_unregister_zone);
655
656struct powercap_control_type *powercap_register_control_type(
657 struct powercap_control_type *control_type,
658 const char *name,
659 const struct powercap_control_type_ops *ops)
660{
661 int result;
662
663 if (!name)
664 return ERR_PTR(-EINVAL);
665 if (control_type) {
666 if (!ops || !ops->release)
667 return ERR_PTR(-EINVAL);
668 memset(control_type, 0, sizeof(*control_type));
669 } else {
670 control_type = kzalloc(sizeof(*control_type), GFP_KERNEL);
671 if (!control_type)
672 return ERR_PTR(-ENOMEM);
673 control_type->allocated = true;
674 }
675 mutex_init(&control_type->lock);
676 control_type->ops = ops;
677 INIT_LIST_HEAD(&control_type->node);
678 control_type->dev.class = &powercap_class;
08ff4cbe 679 dev_set_name(&control_type->dev, "%s", name);
75d2364e
SP
680 result = device_register(&control_type->dev);
681 if (result) {
682 if (control_type->allocated)
683 kfree(control_type);
684 return ERR_PTR(result);
685 }
686 idr_init(&control_type->idr);
687
688 mutex_lock(&powercap_cntrl_list_lock);
689 list_add_tail(&control_type->node, &powercap_cntrl_list);
690 mutex_unlock(&powercap_cntrl_list_lock);
691
692 return control_type;
693}
694EXPORT_SYMBOL_GPL(powercap_register_control_type);
695
696int powercap_unregister_control_type(struct powercap_control_type *control_type)
697{
698 struct powercap_control_type *pos = NULL;
699
700 if (control_type->nr_zones) {
701 dev_err(&control_type->dev, "Zones of this type still not freed\n");
702 return -EINVAL;
703 }
704 mutex_lock(&powercap_cntrl_list_lock);
705 list_for_each_entry(pos, &powercap_cntrl_list, node) {
706 if (pos == control_type) {
707 list_del(&control_type->node);
708 mutex_unlock(&powercap_cntrl_list_lock);
709 device_unregister(&control_type->dev);
710 return 0;
711 }
712 }
713 mutex_unlock(&powercap_cntrl_list_lock);
714
715 return -ENODEV;
716}
717EXPORT_SYMBOL_GPL(powercap_unregister_control_type);
718
719static int __init powercap_init(void)
720{
721 int result = 0;
722
723 result = seed_constraint_attributes();
724 if (result)
725 return result;
726
727 result = class_register(&powercap_class);
728
729 return result;
730}
731
732device_initcall(powercap_init);
733
734MODULE_DESCRIPTION("PowerCap sysfs Driver");
735MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
736MODULE_LICENSE("GPL v2");