powercap_sys.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  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. #include <linux/module.h>
  19. #include <linux/device.h>
  20. #include <linux/err.h>
  21. #include <linux/slab.h>
  22. #include <linux/powercap.h>
  23. #define to_powercap_zone(n) container_of(n, struct powercap_zone, dev)
  24. #define to_powercap_control_type(n) \
  25. container_of(n, struct powercap_control_type, dev)
  26. /* Power zone show function */
  27. #define define_power_zone_show(_attr) \
  28. static ssize_t _attr##_show(struct device *dev, \
  29. struct device_attribute *dev_attr,\
  30. char *buf) \
  31. { \
  32. u64 value; \
  33. ssize_t len = -EINVAL; \
  34. struct powercap_zone *power_zone = to_powercap_zone(dev); \
  35. \
  36. if (power_zone->ops->get_##_attr) { \
  37. if (!power_zone->ops->get_##_attr(power_zone, &value)) \
  38. len = sprintf(buf, "%lld\n", value); \
  39. } \
  40. \
  41. return len; \
  42. }
  43. /* The only meaningful input is 0 (reset), others are silently ignored */
  44. #define define_power_zone_store(_attr) \
  45. static ssize_t _attr##_store(struct device *dev,\
  46. struct device_attribute *dev_attr, \
  47. const char *buf, size_t count) \
  48. { \
  49. int err; \
  50. struct powercap_zone *power_zone = to_powercap_zone(dev); \
  51. u64 value; \
  52. \
  53. err = kstrtoull(buf, 10, &value); \
  54. if (err) \
  55. return -EINVAL; \
  56. if (value) \
  57. return count; \
  58. if (power_zone->ops->reset_##_attr) { \
  59. if (!power_zone->ops->reset_##_attr(power_zone)) \
  60. return count; \
  61. } \
  62. \
  63. return -EINVAL; \
  64. }
  65. /* Power zone constraint show function */
  66. #define define_power_zone_constraint_show(_attr) \
  67. static ssize_t show_constraint_##_attr(struct device *dev, \
  68. struct device_attribute *dev_attr,\
  69. char *buf) \
  70. { \
  71. u64 value; \
  72. ssize_t len = -ENODATA; \
  73. struct powercap_zone *power_zone = to_powercap_zone(dev); \
  74. int id; \
  75. struct powercap_zone_constraint *pconst;\
  76. \
  77. if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \
  78. return -EINVAL; \
  79. if (id >= power_zone->const_id_cnt) \
  80. return -EINVAL; \
  81. pconst = &power_zone->constraints[id]; \
  82. if (pconst && pconst->ops && pconst->ops->get_##_attr) { \
  83. if (!pconst->ops->get_##_attr(power_zone, id, &value)) \
  84. len = sprintf(buf, "%lld\n", value); \
  85. } \
  86. \
  87. return len; \
  88. }
  89. /* Power zone constraint store function */
  90. #define define_power_zone_constraint_store(_attr) \
  91. static ssize_t store_constraint_##_attr(struct device *dev,\
  92. struct device_attribute *dev_attr, \
  93. const char *buf, size_t count) \
  94. { \
  95. int err; \
  96. u64 value; \
  97. struct powercap_zone *power_zone = to_powercap_zone(dev); \
  98. int id; \
  99. struct powercap_zone_constraint *pconst;\
  100. \
  101. if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \
  102. return -EINVAL; \
  103. if (id >= power_zone->const_id_cnt) \
  104. return -EINVAL; \
  105. pconst = &power_zone->constraints[id]; \
  106. err = kstrtoull(buf, 10, &value); \
  107. if (err) \
  108. return -EINVAL; \
  109. if (pconst && pconst->ops && pconst->ops->set_##_attr) { \
  110. if (!pconst->ops->set_##_attr(power_zone, id, value)) \
  111. return count; \
  112. } \
  113. \
  114. return -ENODATA; \
  115. }
  116. /* Power zone information callbacks */
  117. define_power_zone_show(power_uw);
  118. define_power_zone_show(max_power_range_uw);
  119. define_power_zone_show(energy_uj);
  120. define_power_zone_store(energy_uj);
  121. define_power_zone_show(max_energy_range_uj);
  122. /* Power zone attributes */
  123. static DEVICE_ATTR_RO(max_power_range_uw);
  124. static DEVICE_ATTR_RO(power_uw);
  125. static DEVICE_ATTR_RO(max_energy_range_uj);
  126. static DEVICE_ATTR_RW(energy_uj);
  127. /* Power zone constraint attributes callbacks */
  128. define_power_zone_constraint_show(power_limit_uw);
  129. define_power_zone_constraint_store(power_limit_uw);
  130. define_power_zone_constraint_show(time_window_us);
  131. define_power_zone_constraint_store(time_window_us);
  132. define_power_zone_constraint_show(max_power_uw);
  133. define_power_zone_constraint_show(min_power_uw);
  134. define_power_zone_constraint_show(max_time_window_us);
  135. define_power_zone_constraint_show(min_time_window_us);
  136. /* For one time seeding of constraint device attributes */
  137. struct powercap_constraint_attr {
  138. struct device_attribute power_limit_attr;
  139. struct device_attribute time_window_attr;
  140. struct device_attribute max_power_attr;
  141. struct device_attribute min_power_attr;
  142. struct device_attribute max_time_window_attr;
  143. struct device_attribute min_time_window_attr;
  144. struct device_attribute name_attr;
  145. };
  146. static struct powercap_constraint_attr
  147. constraint_attrs[MAX_CONSTRAINTS_PER_ZONE];
  148. /* A list of powercap control_types */
  149. static LIST_HEAD(powercap_cntrl_list);
  150. /* Mutex to protect list of powercap control_types */
  151. static DEFINE_MUTEX(powercap_cntrl_list_lock);
  152. #define POWERCAP_CONSTRAINT_NAME_LEN 30 /* Some limit to avoid overflow */
  153. static ssize_t show_constraint_name(struct device *dev,
  154. struct device_attribute *dev_attr,
  155. char *buf)
  156. {
  157. const char *name;
  158. struct powercap_zone *power_zone = to_powercap_zone(dev);
  159. int id;
  160. ssize_t len = -ENODATA;
  161. struct powercap_zone_constraint *pconst;
  162. if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id))
  163. return -EINVAL;
  164. if (id >= power_zone->const_id_cnt)
  165. return -EINVAL;
  166. pconst = &power_zone->constraints[id];
  167. if (pconst && pconst->ops && pconst->ops->get_name) {
  168. name = pconst->ops->get_name(power_zone, id);
  169. if (name) {
  170. snprintf(buf, POWERCAP_CONSTRAINT_NAME_LEN,
  171. "%s\n", name);
  172. buf[POWERCAP_CONSTRAINT_NAME_LEN] = '\0';
  173. len = strlen(buf);
  174. }
  175. }
  176. return len;
  177. }
  178. static int create_constraint_attribute(int id, const char *name,
  179. int mode,
  180. struct device_attribute *dev_attr,
  181. ssize_t (*show)(struct device *,
  182. struct device_attribute *, char *),
  183. ssize_t (*store)(struct device *,
  184. struct device_attribute *,
  185. const char *, size_t)
  186. )
  187. {
  188. dev_attr->attr.name = kasprintf(GFP_KERNEL, "constraint_%d_%s",
  189. id, name);
  190. if (!dev_attr->attr.name)
  191. return -ENOMEM;
  192. dev_attr->attr.mode = mode;
  193. dev_attr->show = show;
  194. dev_attr->store = store;
  195. return 0;
  196. }
  197. static void free_constraint_attributes(void)
  198. {
  199. int i;
  200. for (i = 0; i < MAX_CONSTRAINTS_PER_ZONE; ++i) {
  201. kfree(constraint_attrs[i].power_limit_attr.attr.name);
  202. kfree(constraint_attrs[i].time_window_attr.attr.name);
  203. kfree(constraint_attrs[i].name_attr.attr.name);
  204. kfree(constraint_attrs[i].max_power_attr.attr.name);
  205. kfree(constraint_attrs[i].min_power_attr.attr.name);
  206. kfree(constraint_attrs[i].max_time_window_attr.attr.name);
  207. kfree(constraint_attrs[i].min_time_window_attr.attr.name);
  208. }
  209. }
  210. static int seed_constraint_attributes(void)
  211. {
  212. int i;
  213. int ret;
  214. for (i = 0; i < MAX_CONSTRAINTS_PER_ZONE; ++i) {
  215. ret = create_constraint_attribute(i, "power_limit_uw",
  216. S_IWUSR | S_IRUGO,
  217. &constraint_attrs[i].power_limit_attr,
  218. show_constraint_power_limit_uw,
  219. store_constraint_power_limit_uw);
  220. if (ret)
  221. goto err_alloc;
  222. ret = create_constraint_attribute(i, "time_window_us",
  223. S_IWUSR | S_IRUGO,
  224. &constraint_attrs[i].time_window_attr,
  225. show_constraint_time_window_us,
  226. store_constraint_time_window_us);
  227. if (ret)
  228. goto err_alloc;
  229. ret = create_constraint_attribute(i, "name", S_IRUGO,
  230. &constraint_attrs[i].name_attr,
  231. show_constraint_name,
  232. NULL);
  233. if (ret)
  234. goto err_alloc;
  235. ret = create_constraint_attribute(i, "max_power_uw", S_IRUGO,
  236. &constraint_attrs[i].max_power_attr,
  237. show_constraint_max_power_uw,
  238. NULL);
  239. if (ret)
  240. goto err_alloc;
  241. ret = create_constraint_attribute(i, "min_power_uw", S_IRUGO,
  242. &constraint_attrs[i].min_power_attr,
  243. show_constraint_min_power_uw,
  244. NULL);
  245. if (ret)
  246. goto err_alloc;
  247. ret = create_constraint_attribute(i, "max_time_window_us",
  248. S_IRUGO,
  249. &constraint_attrs[i].max_time_window_attr,
  250. show_constraint_max_time_window_us,
  251. NULL);
  252. if (ret)
  253. goto err_alloc;
  254. ret = create_constraint_attribute(i, "min_time_window_us",
  255. S_IRUGO,
  256. &constraint_attrs[i].min_time_window_attr,
  257. show_constraint_min_time_window_us,
  258. NULL);
  259. if (ret)
  260. goto err_alloc;
  261. }
  262. return 0;
  263. err_alloc:
  264. free_constraint_attributes();
  265. return ret;
  266. }
  267. static int create_constraints(struct powercap_zone *power_zone,
  268. int nr_constraints,
  269. struct powercap_zone_constraint_ops *const_ops)
  270. {
  271. int i;
  272. int ret = 0;
  273. int count;
  274. struct powercap_zone_constraint *pconst;
  275. if (!power_zone || !const_ops || !const_ops->get_power_limit_uw ||
  276. !const_ops->set_power_limit_uw ||
  277. !const_ops->get_time_window_us ||
  278. !const_ops->set_time_window_us)
  279. return -EINVAL;
  280. count = power_zone->zone_attr_count;
  281. for (i = 0; i < nr_constraints; ++i) {
  282. pconst = &power_zone->constraints[i];
  283. pconst->ops = const_ops;
  284. pconst->id = power_zone->const_id_cnt;
  285. power_zone->const_id_cnt++;
  286. power_zone->zone_dev_attrs[count++] =
  287. &constraint_attrs[i].power_limit_attr.attr;
  288. power_zone->zone_dev_attrs[count++] =
  289. &constraint_attrs[i].time_window_attr.attr;
  290. if (pconst->ops->get_name)
  291. power_zone->zone_dev_attrs[count++] =
  292. &constraint_attrs[i].name_attr.attr;
  293. if (pconst->ops->get_max_power_uw)
  294. power_zone->zone_dev_attrs[count++] =
  295. &constraint_attrs[i].max_power_attr.attr;
  296. if (pconst->ops->get_min_power_uw)
  297. power_zone->zone_dev_attrs[count++] =
  298. &constraint_attrs[i].min_power_attr.attr;
  299. if (pconst->ops->get_max_time_window_us)
  300. power_zone->zone_dev_attrs[count++] =
  301. &constraint_attrs[i].max_time_window_attr.attr;
  302. if (pconst->ops->get_min_time_window_us)
  303. power_zone->zone_dev_attrs[count++] =
  304. &constraint_attrs[i].min_time_window_attr.attr;
  305. }
  306. power_zone->zone_attr_count = count;
  307. return ret;
  308. }
  309. static bool control_type_valid(void *control_type)
  310. {
  311. struct powercap_control_type *pos = NULL;
  312. bool found = false;
  313. mutex_lock(&powercap_cntrl_list_lock);
  314. list_for_each_entry(pos, &powercap_cntrl_list, node) {
  315. if (pos == control_type) {
  316. found = true;
  317. break;
  318. }
  319. }
  320. mutex_unlock(&powercap_cntrl_list_lock);
  321. return found;
  322. }
  323. static ssize_t name_show(struct device *dev,
  324. struct device_attribute *attr,
  325. char *buf)
  326. {
  327. struct powercap_zone *power_zone = to_powercap_zone(dev);
  328. return sprintf(buf, "%s\n", power_zone->name);
  329. }
  330. static DEVICE_ATTR_RO(name);
  331. /* Create zone and attributes in sysfs */
  332. static void create_power_zone_common_attributes(
  333. struct powercap_zone *power_zone)
  334. {
  335. int count = 0;
  336. power_zone->zone_dev_attrs[count++] = &dev_attr_name.attr;
  337. if (power_zone->ops->get_max_energy_range_uj)
  338. power_zone->zone_dev_attrs[count++] =
  339. &dev_attr_max_energy_range_uj.attr;
  340. if (power_zone->ops->get_energy_uj) {
  341. if (power_zone->ops->reset_energy_uj)
  342. dev_attr_energy_uj.attr.mode = S_IWUSR | S_IRUGO;
  343. else
  344. dev_attr_energy_uj.attr.mode = S_IRUGO;
  345. power_zone->zone_dev_attrs[count++] =
  346. &dev_attr_energy_uj.attr;
  347. }
  348. if (power_zone->ops->get_power_uw)
  349. power_zone->zone_dev_attrs[count++] =
  350. &dev_attr_power_uw.attr;
  351. if (power_zone->ops->get_max_power_range_uw)
  352. power_zone->zone_dev_attrs[count++] =
  353. &dev_attr_max_power_range_uw.attr;
  354. power_zone->zone_dev_attrs[count] = NULL;
  355. power_zone->zone_attr_count = count;
  356. }
  357. static void powercap_release(struct device *dev)
  358. {
  359. bool allocated;
  360. if (dev->parent) {
  361. struct powercap_zone *power_zone = to_powercap_zone(dev);
  362. /* Store flag as the release() may free memory */
  363. allocated = power_zone->allocated;
  364. /* Remove id from parent idr struct */
  365. idr_remove(power_zone->parent_idr, power_zone->id);
  366. /* Destroy idrs allocated for this zone */
  367. idr_destroy(&power_zone->idr);
  368. kfree(power_zone->name);
  369. kfree(power_zone->zone_dev_attrs);
  370. kfree(power_zone->constraints);
  371. if (power_zone->ops->release)
  372. power_zone->ops->release(power_zone);
  373. if (allocated)
  374. kfree(power_zone);
  375. } else {
  376. struct powercap_control_type *control_type =
  377. to_powercap_control_type(dev);
  378. /* Store flag as the release() may free memory */
  379. allocated = control_type->allocated;
  380. idr_destroy(&control_type->idr);
  381. mutex_destroy(&control_type->lock);
  382. if (control_type->ops && control_type->ops->release)
  383. control_type->ops->release(control_type);
  384. if (allocated)
  385. kfree(control_type);
  386. }
  387. }
  388. static ssize_t enabled_show(struct device *dev,
  389. struct device_attribute *attr,
  390. char *buf)
  391. {
  392. bool mode = true;
  393. /* Default is enabled */
  394. if (dev->parent) {
  395. struct powercap_zone *power_zone = to_powercap_zone(dev);
  396. if (power_zone->ops->get_enable)
  397. if (power_zone->ops->get_enable(power_zone, &mode))
  398. mode = false;
  399. } else {
  400. struct powercap_control_type *control_type =
  401. to_powercap_control_type(dev);
  402. if (control_type->ops && control_type->ops->get_enable)
  403. if (control_type->ops->get_enable(control_type, &mode))
  404. mode = false;
  405. }
  406. return sprintf(buf, "%d\n", mode);
  407. }
  408. static ssize_t enabled_store(struct device *dev,
  409. struct device_attribute *attr,
  410. const char *buf, size_t len)
  411. {
  412. bool mode;
  413. if (strtobool(buf, &mode))
  414. return -EINVAL;
  415. if (dev->parent) {
  416. struct powercap_zone *power_zone = to_powercap_zone(dev);
  417. if (power_zone->ops->set_enable)
  418. if (!power_zone->ops->set_enable(power_zone, mode))
  419. return len;
  420. } else {
  421. struct powercap_control_type *control_type =
  422. to_powercap_control_type(dev);
  423. if (control_type->ops && control_type->ops->set_enable)
  424. if (!control_type->ops->set_enable(control_type, mode))
  425. return len;
  426. }
  427. return -ENOSYS;
  428. }
  429. static DEVICE_ATTR_RW(enabled);
  430. static struct attribute *powercap_attrs[] = {
  431. &dev_attr_enabled.attr,
  432. NULL,
  433. };
  434. ATTRIBUTE_GROUPS(powercap);
  435. static struct class powercap_class = {
  436. .name = "powercap",
  437. .dev_release = powercap_release,
  438. .dev_groups = powercap_groups,
  439. };
  440. struct powercap_zone *powercap_register_zone(
  441. struct powercap_zone *power_zone,
  442. struct powercap_control_type *control_type,
  443. const char *name,
  444. struct powercap_zone *parent,
  445. const struct powercap_zone_ops *ops,
  446. int nr_constraints,
  447. struct powercap_zone_constraint_ops *const_ops)
  448. {
  449. int result;
  450. int nr_attrs;
  451. if (!name || !control_type || !ops ||
  452. nr_constraints > MAX_CONSTRAINTS_PER_ZONE ||
  453. (!ops->get_energy_uj && !ops->get_power_uw) ||
  454. !control_type_valid(control_type))
  455. return ERR_PTR(-EINVAL);
  456. if (power_zone) {
  457. if (!ops->release)
  458. return ERR_PTR(-EINVAL);
  459. memset(power_zone, 0, sizeof(*power_zone));
  460. } else {
  461. power_zone = kzalloc(sizeof(*power_zone), GFP_KERNEL);
  462. if (!power_zone)
  463. return ERR_PTR(-ENOMEM);
  464. power_zone->allocated = true;
  465. }
  466. power_zone->ops = ops;
  467. power_zone->control_type_inst = control_type;
  468. if (!parent) {
  469. power_zone->dev.parent = &control_type->dev;
  470. power_zone->parent_idr = &control_type->idr;
  471. } else {
  472. power_zone->dev.parent = &parent->dev;
  473. power_zone->parent_idr = &parent->idr;
  474. }
  475. power_zone->dev.class = &powercap_class;
  476. mutex_lock(&control_type->lock);
  477. /* Using idr to get the unique id */
  478. result = idr_alloc(power_zone->parent_idr, NULL, 0, 0, GFP_KERNEL);
  479. if (result < 0)
  480. goto err_idr_alloc;
  481. power_zone->id = result;
  482. idr_init(&power_zone->idr);
  483. result = -ENOMEM;
  484. power_zone->name = kstrdup(name, GFP_KERNEL);
  485. if (!power_zone->name)
  486. goto err_name_alloc;
  487. dev_set_name(&power_zone->dev, "%s:%x",
  488. dev_name(power_zone->dev.parent),
  489. power_zone->id);
  490. power_zone->constraints = kzalloc(sizeof(*power_zone->constraints) *
  491. nr_constraints, GFP_KERNEL);
  492. if (!power_zone->constraints)
  493. goto err_const_alloc;
  494. nr_attrs = nr_constraints * POWERCAP_CONSTRAINTS_ATTRS +
  495. POWERCAP_ZONE_MAX_ATTRS + 1;
  496. power_zone->zone_dev_attrs = kzalloc(sizeof(void *) *
  497. nr_attrs, GFP_KERNEL);
  498. if (!power_zone->zone_dev_attrs)
  499. goto err_attr_alloc;
  500. create_power_zone_common_attributes(power_zone);
  501. result = create_constraints(power_zone, nr_constraints, const_ops);
  502. if (result)
  503. goto err_dev_ret;
  504. power_zone->zone_dev_attrs[power_zone->zone_attr_count] = NULL;
  505. power_zone->dev_zone_attr_group.attrs = power_zone->zone_dev_attrs;
  506. power_zone->dev_attr_groups[0] = &power_zone->dev_zone_attr_group;
  507. power_zone->dev_attr_groups[1] = NULL;
  508. power_zone->dev.groups = power_zone->dev_attr_groups;
  509. result = device_register(&power_zone->dev);
  510. if (result)
  511. goto err_dev_ret;
  512. control_type->nr_zones++;
  513. mutex_unlock(&control_type->lock);
  514. return power_zone;
  515. err_dev_ret:
  516. kfree(power_zone->zone_dev_attrs);
  517. err_attr_alloc:
  518. kfree(power_zone->constraints);
  519. err_const_alloc:
  520. kfree(power_zone->name);
  521. err_name_alloc:
  522. idr_remove(power_zone->parent_idr, power_zone->id);
  523. err_idr_alloc:
  524. if (power_zone->allocated)
  525. kfree(power_zone);
  526. mutex_unlock(&control_type->lock);
  527. return ERR_PTR(result);
  528. }
  529. EXPORT_SYMBOL_GPL(powercap_register_zone);
  530. int powercap_unregister_zone(struct powercap_control_type *control_type,
  531. struct powercap_zone *power_zone)
  532. {
  533. if (!power_zone || !control_type)
  534. return -EINVAL;
  535. mutex_lock(&control_type->lock);
  536. control_type->nr_zones--;
  537. mutex_unlock(&control_type->lock);
  538. device_unregister(&power_zone->dev);
  539. return 0;
  540. }
  541. EXPORT_SYMBOL_GPL(powercap_unregister_zone);
  542. struct powercap_control_type *powercap_register_control_type(
  543. struct powercap_control_type *control_type,
  544. const char *name,
  545. const struct powercap_control_type_ops *ops)
  546. {
  547. int result;
  548. if (!name)
  549. return ERR_PTR(-EINVAL);
  550. if (control_type) {
  551. if (!ops || !ops->release)
  552. return ERR_PTR(-EINVAL);
  553. memset(control_type, 0, sizeof(*control_type));
  554. } else {
  555. control_type = kzalloc(sizeof(*control_type), GFP_KERNEL);
  556. if (!control_type)
  557. return ERR_PTR(-ENOMEM);
  558. control_type->allocated = true;
  559. }
  560. mutex_init(&control_type->lock);
  561. control_type->ops = ops;
  562. INIT_LIST_HEAD(&control_type->node);
  563. control_type->dev.class = &powercap_class;
  564. dev_set_name(&control_type->dev, "%s", name);
  565. result = device_register(&control_type->dev);
  566. if (result) {
  567. if (control_type->allocated)
  568. kfree(control_type);
  569. return ERR_PTR(result);
  570. }
  571. idr_init(&control_type->idr);
  572. mutex_lock(&powercap_cntrl_list_lock);
  573. list_add_tail(&control_type->node, &powercap_cntrl_list);
  574. mutex_unlock(&powercap_cntrl_list_lock);
  575. return control_type;
  576. }
  577. EXPORT_SYMBOL_GPL(powercap_register_control_type);
  578. int powercap_unregister_control_type(struct powercap_control_type *control_type)
  579. {
  580. struct powercap_control_type *pos = NULL;
  581. if (control_type->nr_zones) {
  582. dev_err(&control_type->dev, "Zones of this type still not freed\n");
  583. return -EINVAL;
  584. }
  585. mutex_lock(&powercap_cntrl_list_lock);
  586. list_for_each_entry(pos, &powercap_cntrl_list, node) {
  587. if (pos == control_type) {
  588. list_del(&control_type->node);
  589. mutex_unlock(&powercap_cntrl_list_lock);
  590. device_unregister(&control_type->dev);
  591. return 0;
  592. }
  593. }
  594. mutex_unlock(&powercap_cntrl_list_lock);
  595. return -ENODEV;
  596. }
  597. EXPORT_SYMBOL_GPL(powercap_unregister_control_type);
  598. static int __init powercap_init(void)
  599. {
  600. int result = 0;
  601. result = seed_constraint_attributes();
  602. if (result)
  603. return result;
  604. result = class_register(&powercap_class);
  605. return result;
  606. }
  607. device_initcall(powercap_init);
  608. MODULE_DESCRIPTION("PowerCap sysfs Driver");
  609. MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
  610. MODULE_LICENSE("GPL v2");