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