Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.14 880 lines 22 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * thermal.c - sysfs interface of thermal devices 4 * 5 * Copyright (C) 2016 Eduardo Valentin <edubezval@gmail.com> 6 * 7 * Highly based on original thermal_core.c 8 * Copyright (C) 2008 Intel Corp 9 * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> 10 * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> 11 */ 12 13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 14 15#include <linux/container_of.h> 16#include <linux/sysfs.h> 17#include <linux/device.h> 18#include <linux/err.h> 19#include <linux/slab.h> 20#include <linux/string.h> 21#include <linux/jiffies.h> 22 23#include "thermal_core.h" 24 25/* sys I/F for thermal zone */ 26 27static ssize_t 28type_show(struct device *dev, struct device_attribute *attr, char *buf) 29{ 30 struct thermal_zone_device *tz = to_thermal_zone(dev); 31 32 return sprintf(buf, "%s\n", tz->type); 33} 34 35static ssize_t 36temp_show(struct device *dev, struct device_attribute *attr, char *buf) 37{ 38 struct thermal_zone_device *tz = to_thermal_zone(dev); 39 int temperature, ret; 40 41 ret = thermal_zone_get_temp(tz, &temperature); 42 43 if (ret) 44 return ret; 45 46 return sprintf(buf, "%d\n", temperature); 47} 48 49static ssize_t 50mode_show(struct device *dev, struct device_attribute *attr, char *buf) 51{ 52 struct thermal_zone_device *tz = to_thermal_zone(dev); 53 54 guard(thermal_zone)(tz); 55 56 if (tz->mode == THERMAL_DEVICE_ENABLED) 57 return sprintf(buf, "enabled\n"); 58 59 return sprintf(buf, "disabled\n"); 60} 61 62static ssize_t 63mode_store(struct device *dev, struct device_attribute *attr, 64 const char *buf, size_t count) 65{ 66 struct thermal_zone_device *tz = to_thermal_zone(dev); 67 int result; 68 69 if (!strncmp(buf, "enabled", sizeof("enabled") - 1)) 70 result = thermal_zone_device_enable(tz); 71 else if (!strncmp(buf, "disabled", sizeof("disabled") - 1)) 72 result = thermal_zone_device_disable(tz); 73 else 74 result = -EINVAL; 75 76 if (result) 77 return result; 78 79 return count; 80} 81 82#define thermal_trip_of_attr(_ptr_, _attr_) \ 83 ({ \ 84 struct thermal_trip_desc *td; \ 85 \ 86 td = container_of(_ptr_, struct thermal_trip_desc, \ 87 trip_attrs._attr_.attr); \ 88 &td->trip; \ 89 }) 90 91static ssize_t 92trip_point_type_show(struct device *dev, struct device_attribute *attr, 93 char *buf) 94{ 95 struct thermal_trip *trip = thermal_trip_of_attr(attr, type); 96 97 return sprintf(buf, "%s\n", thermal_trip_type_name(trip->type)); 98} 99 100static ssize_t 101trip_point_temp_store(struct device *dev, struct device_attribute *attr, 102 const char *buf, size_t count) 103{ 104 struct thermal_trip *trip = thermal_trip_of_attr(attr, temp); 105 struct thermal_zone_device *tz = to_thermal_zone(dev); 106 int temp; 107 108 if (kstrtoint(buf, 10, &temp)) 109 return -EINVAL; 110 111 guard(thermal_zone)(tz); 112 113 if (temp == trip->temperature) 114 return count; 115 116 /* Arrange the condition to avoid integer overflows. */ 117 if (temp != THERMAL_TEMP_INVALID && 118 temp <= trip->hysteresis + THERMAL_TEMP_INVALID) 119 return -EINVAL; 120 121 if (tz->ops.set_trip_temp) { 122 int ret; 123 124 ret = tz->ops.set_trip_temp(tz, trip, temp); 125 if (ret) 126 return ret; 127 } 128 129 thermal_zone_set_trip_temp(tz, trip, temp); 130 131 __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED); 132 133 return count; 134} 135 136static ssize_t 137trip_point_temp_show(struct device *dev, struct device_attribute *attr, 138 char *buf) 139{ 140 struct thermal_trip *trip = thermal_trip_of_attr(attr, temp); 141 142 return sprintf(buf, "%d\n", READ_ONCE(trip->temperature)); 143} 144 145static ssize_t 146trip_point_hyst_store(struct device *dev, struct device_attribute *attr, 147 const char *buf, size_t count) 148{ 149 struct thermal_trip *trip = thermal_trip_of_attr(attr, hyst); 150 struct thermal_zone_device *tz = to_thermal_zone(dev); 151 int hyst; 152 153 if (kstrtoint(buf, 10, &hyst) || hyst < 0) 154 return -EINVAL; 155 156 guard(thermal_zone)(tz); 157 158 if (hyst == trip->hysteresis) 159 return count; 160 161 /* 162 * Allow the hysteresis to be updated when the temperature is invalid 163 * to allow user space to avoid having to adjust hysteresis after a 164 * valid temperature has been set, but in that case just change the 165 * value and do nothing else. 166 */ 167 if (trip->temperature == THERMAL_TEMP_INVALID) { 168 WRITE_ONCE(trip->hysteresis, hyst); 169 return count; 170 } 171 172 if (trip->temperature - hyst <= THERMAL_TEMP_INVALID) 173 return -EINVAL; 174 175 thermal_zone_set_trip_hyst(tz, trip, hyst); 176 177 __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED); 178 179 return count; 180} 181 182static ssize_t 183trip_point_hyst_show(struct device *dev, struct device_attribute *attr, 184 char *buf) 185{ 186 struct thermal_trip *trip = thermal_trip_of_attr(attr, hyst); 187 188 return sprintf(buf, "%d\n", READ_ONCE(trip->hysteresis)); 189} 190 191static ssize_t 192policy_store(struct device *dev, struct device_attribute *attr, 193 const char *buf, size_t count) 194{ 195 struct thermal_zone_device *tz = to_thermal_zone(dev); 196 char name[THERMAL_NAME_LENGTH]; 197 int ret; 198 199 snprintf(name, sizeof(name), "%s", buf); 200 201 ret = thermal_zone_device_set_policy(tz, name); 202 if (!ret) 203 ret = count; 204 205 return ret; 206} 207 208static ssize_t 209policy_show(struct device *dev, struct device_attribute *devattr, char *buf) 210{ 211 struct thermal_zone_device *tz = to_thermal_zone(dev); 212 213 return sprintf(buf, "%s\n", tz->governor->name); 214} 215 216static ssize_t 217available_policies_show(struct device *dev, struct device_attribute *devattr, 218 char *buf) 219{ 220 return thermal_build_list_of_policies(buf); 221} 222 223#if (IS_ENABLED(CONFIG_THERMAL_EMULATION)) 224static ssize_t 225emul_temp_store(struct device *dev, struct device_attribute *attr, 226 const char *buf, size_t count) 227{ 228 struct thermal_zone_device *tz = to_thermal_zone(dev); 229 int temperature; 230 231 if (kstrtoint(buf, 10, &temperature)) 232 return -EINVAL; 233 234 guard(thermal_zone)(tz); 235 236 if (tz->ops.set_emul_temp) { 237 int ret; 238 239 ret = tz->ops.set_emul_temp(tz, temperature); 240 if (ret) 241 return ret; 242 } else { 243 tz->emul_temperature = temperature; 244 } 245 246 __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); 247 248 return count; 249} 250static DEVICE_ATTR_WO(emul_temp); 251#endif 252 253static ssize_t 254sustainable_power_show(struct device *dev, struct device_attribute *devattr, 255 char *buf) 256{ 257 struct thermal_zone_device *tz = to_thermal_zone(dev); 258 259 if (tz->tzp) 260 return sprintf(buf, "%u\n", tz->tzp->sustainable_power); 261 else 262 return -EIO; 263} 264 265static ssize_t 266sustainable_power_store(struct device *dev, struct device_attribute *devattr, 267 const char *buf, size_t count) 268{ 269 struct thermal_zone_device *tz = to_thermal_zone(dev); 270 u32 sustainable_power; 271 272 if (!tz->tzp) 273 return -EIO; 274 275 if (kstrtou32(buf, 10, &sustainable_power)) 276 return -EINVAL; 277 278 tz->tzp->sustainable_power = sustainable_power; 279 280 return count; 281} 282 283#define create_s32_tzp_attr(name) \ 284 static ssize_t \ 285 name##_show(struct device *dev, struct device_attribute *devattr, \ 286 char *buf) \ 287 { \ 288 struct thermal_zone_device *tz = to_thermal_zone(dev); \ 289 \ 290 if (tz->tzp) \ 291 return sprintf(buf, "%d\n", tz->tzp->name); \ 292 else \ 293 return -EIO; \ 294 } \ 295 \ 296 static ssize_t \ 297 name##_store(struct device *dev, struct device_attribute *devattr, \ 298 const char *buf, size_t count) \ 299 { \ 300 struct thermal_zone_device *tz = to_thermal_zone(dev); \ 301 s32 value; \ 302 \ 303 if (!tz->tzp) \ 304 return -EIO; \ 305 \ 306 if (kstrtos32(buf, 10, &value)) \ 307 return -EINVAL; \ 308 \ 309 tz->tzp->name = value; \ 310 \ 311 return count; \ 312 } \ 313 static DEVICE_ATTR_RW(name) 314 315create_s32_tzp_attr(k_po); 316create_s32_tzp_attr(k_pu); 317create_s32_tzp_attr(k_i); 318create_s32_tzp_attr(k_d); 319create_s32_tzp_attr(integral_cutoff); 320create_s32_tzp_attr(slope); 321create_s32_tzp_attr(offset); 322#undef create_s32_tzp_attr 323 324/* 325 * These are thermal zone device attributes that will always be present. 326 * All the attributes created for tzp (create_s32_tzp_attr) also are always 327 * present on the sysfs interface. 328 */ 329static DEVICE_ATTR_RO(type); 330static DEVICE_ATTR_RO(temp); 331static DEVICE_ATTR_RW(policy); 332static DEVICE_ATTR_RO(available_policies); 333static DEVICE_ATTR_RW(sustainable_power); 334 335/* These thermal zone device attributes are created based on conditions */ 336static DEVICE_ATTR_RW(mode); 337 338/* These attributes are unconditionally added to a thermal zone */ 339static struct attribute *thermal_zone_dev_attrs[] = { 340 &dev_attr_type.attr, 341 &dev_attr_temp.attr, 342#if (IS_ENABLED(CONFIG_THERMAL_EMULATION)) 343 &dev_attr_emul_temp.attr, 344#endif 345 &dev_attr_policy.attr, 346 &dev_attr_available_policies.attr, 347 &dev_attr_sustainable_power.attr, 348 &dev_attr_k_po.attr, 349 &dev_attr_k_pu.attr, 350 &dev_attr_k_i.attr, 351 &dev_attr_k_d.attr, 352 &dev_attr_integral_cutoff.attr, 353 &dev_attr_slope.attr, 354 &dev_attr_offset.attr, 355 NULL, 356}; 357 358static const struct attribute_group thermal_zone_attribute_group = { 359 .attrs = thermal_zone_dev_attrs, 360}; 361 362static struct attribute *thermal_zone_mode_attrs[] = { 363 &dev_attr_mode.attr, 364 NULL, 365}; 366 367static const struct attribute_group thermal_zone_mode_attribute_group = { 368 .attrs = thermal_zone_mode_attrs, 369}; 370 371static const struct attribute_group *thermal_zone_attribute_groups[] = { 372 &thermal_zone_attribute_group, 373 &thermal_zone_mode_attribute_group, 374 /* This is not NULL terminated as we create the group dynamically */ 375}; 376 377/** 378 * create_trip_attrs() - create attributes for trip points 379 * @tz: the thermal zone device 380 * 381 * helper function to instantiate sysfs entries for every trip 382 * point and its properties of a struct thermal_zone_device. 383 * 384 * Return: 0 on success, the proper error value otherwise. 385 */ 386static int create_trip_attrs(struct thermal_zone_device *tz) 387{ 388 struct thermal_trip_desc *td; 389 struct attribute **attrs; 390 int i; 391 392 attrs = kcalloc(tz->num_trips * 3 + 1, sizeof(*attrs), GFP_KERNEL); 393 if (!attrs) 394 return -ENOMEM; 395 396 i = 0; 397 for_each_trip_desc(tz, td) { 398 struct thermal_trip_attrs *trip_attrs = &td->trip_attrs; 399 400 /* create trip type attribute */ 401 snprintf(trip_attrs->type.name, THERMAL_NAME_LENGTH, 402 "trip_point_%d_type", i); 403 404 sysfs_attr_init(&trip_attrs->type.attr.attr); 405 trip_attrs->type.attr.attr.name = trip_attrs->type.name; 406 trip_attrs->type.attr.attr.mode = S_IRUGO; 407 trip_attrs->type.attr.show = trip_point_type_show; 408 attrs[i] = &trip_attrs->type.attr.attr; 409 410 /* create trip temp attribute */ 411 snprintf(trip_attrs->temp.name, THERMAL_NAME_LENGTH, 412 "trip_point_%d_temp", i); 413 414 sysfs_attr_init(&trip_attrs->temp.attr.attr); 415 trip_attrs->temp.attr.attr.name = trip_attrs->temp.name; 416 trip_attrs->temp.attr.attr.mode = S_IRUGO; 417 trip_attrs->temp.attr.show = trip_point_temp_show; 418 if (td->trip.flags & THERMAL_TRIP_FLAG_RW_TEMP) { 419 trip_attrs->temp.attr.attr.mode |= S_IWUSR; 420 trip_attrs->temp.attr.store = trip_point_temp_store; 421 } 422 attrs[i + tz->num_trips] = &trip_attrs->temp.attr.attr; 423 424 snprintf(trip_attrs->hyst.name, THERMAL_NAME_LENGTH, 425 "trip_point_%d_hyst", i); 426 427 sysfs_attr_init(&trip_attrs->hyst.attr.attr); 428 trip_attrs->hyst.attr.attr.name = trip_attrs->hyst.name; 429 trip_attrs->hyst.attr.attr.mode = S_IRUGO; 430 trip_attrs->hyst.attr.show = trip_point_hyst_show; 431 if (td->trip.flags & THERMAL_TRIP_FLAG_RW_HYST) { 432 trip_attrs->hyst.attr.attr.mode |= S_IWUSR; 433 trip_attrs->hyst.attr.store = trip_point_hyst_store; 434 } 435 attrs[i + 2 * tz->num_trips] = &trip_attrs->hyst.attr.attr; 436 i++; 437 } 438 attrs[tz->num_trips * 3] = NULL; 439 440 tz->trips_attribute_group.attrs = attrs; 441 442 return 0; 443} 444 445/** 446 * destroy_trip_attrs() - destroy attributes for trip points 447 * @tz: the thermal zone device 448 * 449 * helper function to free resources allocated by create_trip_attrs() 450 */ 451static void destroy_trip_attrs(struct thermal_zone_device *tz) 452{ 453 if (tz) 454 kfree(tz->trips_attribute_group.attrs); 455} 456 457int thermal_zone_create_device_groups(struct thermal_zone_device *tz) 458{ 459 const struct attribute_group **groups; 460 int i, size, result; 461 462 /* we need one extra for trips and the NULL to terminate the array */ 463 size = ARRAY_SIZE(thermal_zone_attribute_groups) + 2; 464 /* This also takes care of API requirement to be NULL terminated */ 465 groups = kcalloc(size, sizeof(*groups), GFP_KERNEL); 466 if (!groups) 467 return -ENOMEM; 468 469 for (i = 0; i < size - 2; i++) 470 groups[i] = thermal_zone_attribute_groups[i]; 471 472 if (tz->num_trips) { 473 result = create_trip_attrs(tz); 474 if (result) { 475 kfree(groups); 476 477 return result; 478 } 479 480 groups[size - 2] = &tz->trips_attribute_group; 481 } 482 483 tz->device.groups = groups; 484 485 return 0; 486} 487 488void thermal_zone_destroy_device_groups(struct thermal_zone_device *tz) 489{ 490 if (!tz) 491 return; 492 493 if (tz->num_trips) 494 destroy_trip_attrs(tz); 495 496 kfree(tz->device.groups); 497} 498 499/* sys I/F for cooling device */ 500static ssize_t 501cdev_type_show(struct device *dev, struct device_attribute *attr, char *buf) 502{ 503 struct thermal_cooling_device *cdev = to_cooling_device(dev); 504 505 return sprintf(buf, "%s\n", cdev->type); 506} 507 508static ssize_t max_state_show(struct device *dev, struct device_attribute *attr, 509 char *buf) 510{ 511 struct thermal_cooling_device *cdev = to_cooling_device(dev); 512 513 return sprintf(buf, "%ld\n", cdev->max_state); 514} 515 516static ssize_t cur_state_show(struct device *dev, struct device_attribute *attr, 517 char *buf) 518{ 519 struct thermal_cooling_device *cdev = to_cooling_device(dev); 520 unsigned long state; 521 int ret; 522 523 ret = cdev->ops->get_cur_state(cdev, &state); 524 if (ret) 525 return ret; 526 return sprintf(buf, "%ld\n", state); 527} 528 529static ssize_t 530cur_state_store(struct device *dev, struct device_attribute *attr, 531 const char *buf, size_t count) 532{ 533 struct thermal_cooling_device *cdev = to_cooling_device(dev); 534 unsigned long state; 535 int result; 536 537 if (sscanf(buf, "%ld\n", &state) != 1) 538 return -EINVAL; 539 540 if ((long)state < 0) 541 return -EINVAL; 542 543 /* Requested state should be less than max_state + 1 */ 544 if (state > cdev->max_state) 545 return -EINVAL; 546 547 guard(cooling_dev)(cdev); 548 549 result = cdev->ops->set_cur_state(cdev, state); 550 if (result) 551 return result; 552 553 thermal_cooling_device_stats_update(cdev, state); 554 555 return count; 556} 557 558static struct device_attribute 559dev_attr_cdev_type = __ATTR(type, 0444, cdev_type_show, NULL); 560static DEVICE_ATTR_RO(max_state); 561static DEVICE_ATTR_RW(cur_state); 562 563static struct attribute *cooling_device_attrs[] = { 564 &dev_attr_cdev_type.attr, 565 &dev_attr_max_state.attr, 566 &dev_attr_cur_state.attr, 567 NULL, 568}; 569 570static const struct attribute_group cooling_device_attr_group = { 571 .attrs = cooling_device_attrs, 572}; 573 574static const struct attribute_group *cooling_device_attr_groups[] = { 575 &cooling_device_attr_group, 576 NULL, /* Space allocated for cooling_device_stats_attr_group */ 577 NULL, 578}; 579 580#ifdef CONFIG_THERMAL_STATISTICS 581struct cooling_dev_stats { 582 spinlock_t lock; 583 unsigned int total_trans; 584 unsigned long state; 585 ktime_t last_time; 586 ktime_t *time_in_state; 587 unsigned int *trans_table; 588}; 589 590static void update_time_in_state(struct cooling_dev_stats *stats) 591{ 592 ktime_t now = ktime_get(), delta; 593 594 delta = ktime_sub(now, stats->last_time); 595 stats->time_in_state[stats->state] = 596 ktime_add(stats->time_in_state[stats->state], delta); 597 stats->last_time = now; 598} 599 600void thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev, 601 unsigned long new_state) 602{ 603 struct cooling_dev_stats *stats = cdev->stats; 604 605 lockdep_assert_held(&cdev->lock); 606 607 if (!stats) 608 return; 609 610 spin_lock(&stats->lock); 611 612 if (stats->state == new_state) 613 goto unlock; 614 615 update_time_in_state(stats); 616 stats->trans_table[stats->state * (cdev->max_state + 1) + new_state]++; 617 stats->state = new_state; 618 stats->total_trans++; 619 620unlock: 621 spin_unlock(&stats->lock); 622} 623 624static ssize_t total_trans_show(struct device *dev, 625 struct device_attribute *attr, char *buf) 626{ 627 struct thermal_cooling_device *cdev = to_cooling_device(dev); 628 struct cooling_dev_stats *stats; 629 int ret; 630 631 guard(cooling_dev)(cdev); 632 633 stats = cdev->stats; 634 if (!stats) 635 return 0; 636 637 spin_lock(&stats->lock); 638 ret = sprintf(buf, "%u\n", stats->total_trans); 639 spin_unlock(&stats->lock); 640 641 return ret; 642} 643 644static ssize_t 645time_in_state_ms_show(struct device *dev, struct device_attribute *attr, 646 char *buf) 647{ 648 struct thermal_cooling_device *cdev = to_cooling_device(dev); 649 struct cooling_dev_stats *stats; 650 ssize_t len = 0; 651 int i; 652 653 guard(cooling_dev)(cdev); 654 655 stats = cdev->stats; 656 if (!stats) 657 return 0; 658 659 spin_lock(&stats->lock); 660 661 update_time_in_state(stats); 662 663 for (i = 0; i <= cdev->max_state; i++) { 664 len += sprintf(buf + len, "state%u\t%llu\n", i, 665 ktime_to_ms(stats->time_in_state[i])); 666 } 667 spin_unlock(&stats->lock); 668 669 return len; 670} 671 672static ssize_t 673reset_store(struct device *dev, struct device_attribute *attr, const char *buf, 674 size_t count) 675{ 676 struct thermal_cooling_device *cdev = to_cooling_device(dev); 677 struct cooling_dev_stats *stats; 678 int i, states; 679 680 guard(cooling_dev)(cdev); 681 682 stats = cdev->stats; 683 if (!stats) 684 return count; 685 686 states = cdev->max_state + 1; 687 688 spin_lock(&stats->lock); 689 690 stats->total_trans = 0; 691 stats->last_time = ktime_get(); 692 memset(stats->trans_table, 0, 693 states * states * sizeof(*stats->trans_table)); 694 695 for (i = 0; i < states; i++) 696 stats->time_in_state[i] = ktime_set(0, 0); 697 698 spin_unlock(&stats->lock); 699 700 return count; 701} 702 703static ssize_t trans_table_show(struct device *dev, 704 struct device_attribute *attr, char *buf) 705{ 706 struct thermal_cooling_device *cdev = to_cooling_device(dev); 707 struct cooling_dev_stats *stats; 708 ssize_t len = 0; 709 int i, j; 710 711 guard(cooling_dev)(cdev); 712 713 stats = cdev->stats; 714 if (!stats) 715 return -ENODATA; 716 717 len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n"); 718 len += snprintf(buf + len, PAGE_SIZE - len, " : "); 719 for (i = 0; i <= cdev->max_state; i++) { 720 if (len >= PAGE_SIZE) 721 break; 722 len += snprintf(buf + len, PAGE_SIZE - len, "state%2u ", i); 723 } 724 if (len >= PAGE_SIZE) 725 return PAGE_SIZE; 726 727 len += snprintf(buf + len, PAGE_SIZE - len, "\n"); 728 729 for (i = 0; i <= cdev->max_state; i++) { 730 if (len >= PAGE_SIZE) 731 break; 732 733 len += snprintf(buf + len, PAGE_SIZE - len, "state%2u:", i); 734 735 for (j = 0; j <= cdev->max_state; j++) { 736 if (len >= PAGE_SIZE) 737 break; 738 len += snprintf(buf + len, PAGE_SIZE - len, "%8u ", 739 stats->trans_table[i * (cdev->max_state + 1) + j]); 740 } 741 if (len >= PAGE_SIZE) 742 break; 743 len += snprintf(buf + len, PAGE_SIZE - len, "\n"); 744 } 745 746 if (len >= PAGE_SIZE) { 747 pr_warn_once("Thermal transition table exceeds PAGE_SIZE. Disabling\n"); 748 len = -EFBIG; 749 } 750 751 return len; 752} 753 754static DEVICE_ATTR_RO(total_trans); 755static DEVICE_ATTR_RO(time_in_state_ms); 756static DEVICE_ATTR_WO(reset); 757static DEVICE_ATTR_RO(trans_table); 758 759static struct attribute *cooling_device_stats_attrs[] = { 760 &dev_attr_total_trans.attr, 761 &dev_attr_time_in_state_ms.attr, 762 &dev_attr_reset.attr, 763 &dev_attr_trans_table.attr, 764 NULL 765}; 766 767static const struct attribute_group cooling_device_stats_attr_group = { 768 .attrs = cooling_device_stats_attrs, 769 .name = "stats" 770}; 771 772static void cooling_device_stats_setup(struct thermal_cooling_device *cdev) 773{ 774 const struct attribute_group *stats_attr_group = NULL; 775 struct cooling_dev_stats *stats; 776 /* Total number of states is highest state + 1 */ 777 unsigned long states = cdev->max_state + 1; 778 int var; 779 780 var = sizeof(*stats); 781 var += sizeof(*stats->time_in_state) * states; 782 var += sizeof(*stats->trans_table) * states * states; 783 784 stats = kzalloc(var, GFP_KERNEL); 785 if (!stats) 786 goto out; 787 788 stats->time_in_state = (ktime_t *)(stats + 1); 789 stats->trans_table = (unsigned int *)(stats->time_in_state + states); 790 cdev->stats = stats; 791 stats->last_time = ktime_get(); 792 793 spin_lock_init(&stats->lock); 794 795 stats_attr_group = &cooling_device_stats_attr_group; 796 797out: 798 /* Fill the empty slot left in cooling_device_attr_groups */ 799 var = ARRAY_SIZE(cooling_device_attr_groups) - 2; 800 cooling_device_attr_groups[var] = stats_attr_group; 801} 802 803static void cooling_device_stats_destroy(struct thermal_cooling_device *cdev) 804{ 805 kfree(cdev->stats); 806 cdev->stats = NULL; 807} 808 809#else 810 811static inline void 812cooling_device_stats_setup(struct thermal_cooling_device *cdev) {} 813static inline void 814cooling_device_stats_destroy(struct thermal_cooling_device *cdev) {} 815 816#endif /* CONFIG_THERMAL_STATISTICS */ 817 818void thermal_cooling_device_setup_sysfs(struct thermal_cooling_device *cdev) 819{ 820 cooling_device_stats_setup(cdev); 821 cdev->device.groups = cooling_device_attr_groups; 822} 823 824void thermal_cooling_device_destroy_sysfs(struct thermal_cooling_device *cdev) 825{ 826 cooling_device_stats_destroy(cdev); 827} 828 829void thermal_cooling_device_stats_reinit(struct thermal_cooling_device *cdev) 830{ 831 lockdep_assert_held(&cdev->lock); 832 833 cooling_device_stats_destroy(cdev); 834 cooling_device_stats_setup(cdev); 835} 836 837/* these helper will be used only at the time of bindig */ 838ssize_t 839trip_point_show(struct device *dev, struct device_attribute *attr, char *buf) 840{ 841 struct thermal_zone_device *tz = to_thermal_zone(dev); 842 struct thermal_instance *instance; 843 844 instance = container_of(attr, struct thermal_instance, attr); 845 846 return sprintf(buf, "%d\n", thermal_zone_trip_id(tz, instance->trip)); 847} 848 849ssize_t 850weight_show(struct device *dev, struct device_attribute *attr, char *buf) 851{ 852 struct thermal_instance *instance; 853 854 instance = container_of(attr, struct thermal_instance, weight_attr); 855 856 return sprintf(buf, "%d\n", instance->weight); 857} 858 859ssize_t weight_store(struct device *dev, struct device_attribute *attr, 860 const char *buf, size_t count) 861{ 862 struct thermal_zone_device *tz = to_thermal_zone(dev); 863 struct thermal_instance *instance; 864 int ret, weight; 865 866 ret = kstrtoint(buf, 0, &weight); 867 if (ret) 868 return ret; 869 870 instance = container_of(attr, struct thermal_instance, weight_attr); 871 872 /* Don't race with governors using the 'weight' value */ 873 guard(thermal_zone)(tz); 874 875 instance->weight = weight; 876 877 thermal_governor_update_tz(tz, THERMAL_INSTANCE_WEIGHT_CHANGED); 878 879 return count; 880}