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