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.

Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux

Pull thermal management update from Zhang Rui:

- Fix race condition in imx_thermal_probe() (Mikhail Lappo)

- Add cooling device's statistics in sysfs (Viresh Kumar)

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux:
thermal: Add cooling device's statistics in sysfs
thermal: imx: Fix race condition in imx_thermal_probe()

+283 -5
+31
Documentation/thermal/sysfs-api.txt
··· 255 255 2. sysfs attributes structure 256 256 257 257 RO read only value 258 + WO write only value 258 259 RW read/write value 259 260 260 261 Thermal sysfs attributes will be represented under /sys/class/thermal. ··· 287 286 |---type: Type of the cooling device(processor/fan/...) 288 287 |---max_state: Maximum cooling state of the cooling device 289 288 |---cur_state: Current cooling state of the cooling device 289 + |---stats: Directory containing cooling device's statistics 290 + |---stats/reset: Writing any value resets the statistics 291 + |---stats/time_in_state_ms: Time (msec) spent in various cooling states 292 + |---stats/total_trans: Total number of times cooling state is changed 293 + |---stats/trans_table: Cooing state transition table 290 294 291 295 292 296 Then next two dynamic attributes are created/removed in pairs. They represent ··· 495 489 - cur_state == 0 means no cooling 496 490 - cur_state == max_state means the maximum cooling. 497 491 RW, Required 492 + 493 + stats/reset 494 + Writing any value resets the cooling device's statistics. 495 + WO, Required 496 + 497 + stats/time_in_state_ms: 498 + The amount of time spent by the cooling device in various cooling 499 + states. The output will have "<state> <time>" pair in each line, which 500 + will mean this cooling device spent <time> msec of time at <state>. 501 + Output will have one line for each of the supported states. usertime 502 + units here is 10mS (similar to other time exported in /proc). 503 + RO, Required 504 + 505 + stats/total_trans: 506 + A single positive value showing the total number of times the state of a 507 + cooling device is changed. 508 + RO, Required 509 + 510 + stats/trans_table: 511 + This gives fine grained information about all the cooling state 512 + transitions. The cat output here is a two dimensional matrix, where an 513 + entry <i,j> (row i, column j) represents the number of transitions from 514 + State_i to State_j. If the transition table is bigger than PAGE_SIZE, 515 + reading this will return an -EFBIG error. 516 + RO, Required 498 517 499 518 3. A simple implementation 500 519
+7
drivers/thermal/Kconfig
··· 15 15 16 16 if THERMAL 17 17 18 + config THERMAL_STATISTICS 19 + bool "Thermal state transition statistics" 20 + help 21 + Export thermal state transition statistics information through sysfs. 22 + 23 + If in doubt, say N. 24 + 18 25 config THERMAL_EMERGENCY_POWEROFF_DELAY_MS 19 26 int "Emergency poweroff delay in milli-seconds" 20 27 depends on THERMAL
+3 -3
drivers/thermal/imx_thermal.c
··· 637 637 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); 638 638 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); 639 639 640 + data->irq_enabled = true; 641 + data->mode = THERMAL_DEVICE_ENABLED; 642 + 640 643 ret = devm_request_threaded_irq(&pdev->dev, data->irq, 641 644 imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread, 642 645 0, "imx_thermal", data); ··· 651 648 cpufreq_cpu_put(data->policy); 652 649 return ret; 653 650 } 654 - 655 - data->irq_enabled = true; 656 - data->mode = THERMAL_DEVICE_ENABLED; 657 651 658 652 return 0; 659 653 }
+2 -1
drivers/thermal/thermal_core.c
··· 972 972 cdev->ops = ops; 973 973 cdev->updated = false; 974 974 cdev->device.class = &thermal_class; 975 - thermal_cooling_device_setup_sysfs(cdev); 976 975 cdev->devdata = devdata; 976 + thermal_cooling_device_setup_sysfs(cdev); 977 977 dev_set_name(&cdev->device, "cooling_device%d", cdev->id); 978 978 result = device_register(&cdev->device); 979 979 if (result) { ··· 1106 1106 1107 1107 ida_simple_remove(&thermal_cdev_ida, cdev->id); 1108 1108 device_unregister(&cdev->device); 1109 + thermal_cooling_device_destroy_sysfs(cdev); 1109 1110 } 1110 1111 EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister); 1111 1112
+10
drivers/thermal/thermal_core.h
··· 73 73 int thermal_zone_create_device_groups(struct thermal_zone_device *, int); 74 74 void thermal_zone_destroy_device_groups(struct thermal_zone_device *); 75 75 void thermal_cooling_device_setup_sysfs(struct thermal_cooling_device *); 76 + void thermal_cooling_device_destroy_sysfs(struct thermal_cooling_device *cdev); 76 77 /* used only at binding time */ 77 78 ssize_t 78 79 thermal_cooling_device_trip_point_show(struct device *, ··· 84 83 ssize_t thermal_cooling_device_weight_store(struct device *, 85 84 struct device_attribute *, 86 85 const char *, size_t); 86 + 87 + #ifdef CONFIG_THERMAL_STATISTICS 88 + void thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev, 89 + unsigned long new_state); 90 + #else 91 + static inline void 92 + thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev, 93 + unsigned long new_state) {} 94 + #endif /* CONFIG_THERMAL_STATISTICS */ 87 95 88 96 #ifdef CONFIG_THERMAL_GOV_STEP_WISE 89 97 int thermal_gov_step_wise_register(void);
+4 -1
drivers/thermal/thermal_helpers.c
··· 187 187 if (instance->target > target) 188 188 target = instance->target; 189 189 } 190 - cdev->ops->set_cur_state(cdev, target); 190 + 191 + if (!cdev->ops->set_cur_state(cdev, target)) 192 + thermal_cooling_device_stats_update(cdev, target); 193 + 191 194 cdev->updated = true; 192 195 mutex_unlock(&cdev->lock); 193 196 trace_cdev_update(cdev, target);
+225
drivers/thermal/thermal_sysfs.c
··· 20 20 #include <linux/err.h> 21 21 #include <linux/slab.h> 22 22 #include <linux/string.h> 23 + #include <linux/jiffies.h> 23 24 24 25 #include "thermal_core.h" 25 26 ··· 722 721 result = cdev->ops->set_cur_state(cdev, state); 723 722 if (result) 724 723 return result; 724 + thermal_cooling_device_stats_update(cdev, state); 725 725 return count; 726 726 } 727 727 ··· 747 745 748 746 static const struct attribute_group *cooling_device_attr_groups[] = { 749 747 &cooling_device_attr_group, 748 + NULL, /* Space allocated for cooling_device_stats_attr_group */ 750 749 NULL, 751 750 }; 752 751 752 + #ifdef CONFIG_THERMAL_STATISTICS 753 + struct cooling_dev_stats { 754 + spinlock_t lock; 755 + unsigned int total_trans; 756 + unsigned long state; 757 + unsigned long max_states; 758 + ktime_t last_time; 759 + ktime_t *time_in_state; 760 + unsigned int *trans_table; 761 + }; 762 + 763 + static void update_time_in_state(struct cooling_dev_stats *stats) 764 + { 765 + ktime_t now = ktime_get(), delta; 766 + 767 + delta = ktime_sub(now, stats->last_time); 768 + stats->time_in_state[stats->state] = 769 + ktime_add(stats->time_in_state[stats->state], delta); 770 + stats->last_time = now; 771 + } 772 + 773 + void thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev, 774 + unsigned long new_state) 775 + { 776 + struct cooling_dev_stats *stats = cdev->stats; 777 + 778 + spin_lock(&stats->lock); 779 + 780 + if (stats->state == new_state) 781 + goto unlock; 782 + 783 + update_time_in_state(stats); 784 + stats->trans_table[stats->state * stats->max_states + new_state]++; 785 + stats->state = new_state; 786 + stats->total_trans++; 787 + 788 + unlock: 789 + spin_unlock(&stats->lock); 790 + } 791 + 792 + static ssize_t 793 + thermal_cooling_device_total_trans_show(struct device *dev, 794 + struct device_attribute *attr, 795 + char *buf) 796 + { 797 + struct thermal_cooling_device *cdev = to_cooling_device(dev); 798 + struct cooling_dev_stats *stats = cdev->stats; 799 + int ret; 800 + 801 + spin_lock(&stats->lock); 802 + ret = sprintf(buf, "%u\n", stats->total_trans); 803 + spin_unlock(&stats->lock); 804 + 805 + return ret; 806 + } 807 + 808 + static ssize_t 809 + thermal_cooling_device_time_in_state_show(struct device *dev, 810 + struct device_attribute *attr, 811 + char *buf) 812 + { 813 + struct thermal_cooling_device *cdev = to_cooling_device(dev); 814 + struct cooling_dev_stats *stats = cdev->stats; 815 + ssize_t len = 0; 816 + int i; 817 + 818 + spin_lock(&stats->lock); 819 + update_time_in_state(stats); 820 + 821 + for (i = 0; i < stats->max_states; i++) { 822 + len += sprintf(buf + len, "state%u\t%llu\n", i, 823 + ktime_to_ms(stats->time_in_state[i])); 824 + } 825 + spin_unlock(&stats->lock); 826 + 827 + return len; 828 + } 829 + 830 + static ssize_t 831 + thermal_cooling_device_reset_store(struct device *dev, 832 + struct device_attribute *attr, 833 + const char *buf, size_t count) 834 + { 835 + struct thermal_cooling_device *cdev = to_cooling_device(dev); 836 + struct cooling_dev_stats *stats = cdev->stats; 837 + int i, states = stats->max_states; 838 + 839 + spin_lock(&stats->lock); 840 + 841 + stats->total_trans = 0; 842 + stats->last_time = ktime_get(); 843 + memset(stats->trans_table, 0, 844 + states * states * sizeof(*stats->trans_table)); 845 + 846 + for (i = 0; i < stats->max_states; i++) 847 + stats->time_in_state[i] = ktime_set(0, 0); 848 + 849 + spin_unlock(&stats->lock); 850 + 851 + return count; 852 + } 853 + 854 + static ssize_t 855 + thermal_cooling_device_trans_table_show(struct device *dev, 856 + struct device_attribute *attr, 857 + char *buf) 858 + { 859 + struct thermal_cooling_device *cdev = to_cooling_device(dev); 860 + struct cooling_dev_stats *stats = cdev->stats; 861 + ssize_t len = 0; 862 + int i, j; 863 + 864 + len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n"); 865 + len += snprintf(buf + len, PAGE_SIZE - len, " : "); 866 + for (i = 0; i < stats->max_states; i++) { 867 + if (len >= PAGE_SIZE) 868 + break; 869 + len += snprintf(buf + len, PAGE_SIZE - len, "state%2u ", i); 870 + } 871 + if (len >= PAGE_SIZE) 872 + return PAGE_SIZE; 873 + 874 + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); 875 + 876 + for (i = 0; i < stats->max_states; i++) { 877 + if (len >= PAGE_SIZE) 878 + break; 879 + 880 + len += snprintf(buf + len, PAGE_SIZE - len, "state%2u:", i); 881 + 882 + for (j = 0; j < stats->max_states; j++) { 883 + if (len >= PAGE_SIZE) 884 + break; 885 + len += snprintf(buf + len, PAGE_SIZE - len, "%8u ", 886 + stats->trans_table[i * stats->max_states + j]); 887 + } 888 + if (len >= PAGE_SIZE) 889 + break; 890 + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); 891 + } 892 + 893 + if (len >= PAGE_SIZE) { 894 + pr_warn_once("Thermal transition table exceeds PAGE_SIZE. Disabling\n"); 895 + return -EFBIG; 896 + } 897 + return len; 898 + } 899 + 900 + static DEVICE_ATTR(total_trans, 0444, thermal_cooling_device_total_trans_show, 901 + NULL); 902 + static DEVICE_ATTR(time_in_state_ms, 0444, 903 + thermal_cooling_device_time_in_state_show, NULL); 904 + static DEVICE_ATTR(reset, 0200, NULL, thermal_cooling_device_reset_store); 905 + static DEVICE_ATTR(trans_table, 0444, 906 + thermal_cooling_device_trans_table_show, NULL); 907 + 908 + static struct attribute *cooling_device_stats_attrs[] = { 909 + &dev_attr_total_trans.attr, 910 + &dev_attr_time_in_state_ms.attr, 911 + &dev_attr_reset.attr, 912 + &dev_attr_trans_table.attr, 913 + NULL 914 + }; 915 + 916 + static const struct attribute_group cooling_device_stats_attr_group = { 917 + .attrs = cooling_device_stats_attrs, 918 + .name = "stats" 919 + }; 920 + 921 + static void cooling_device_stats_setup(struct thermal_cooling_device *cdev) 922 + { 923 + struct cooling_dev_stats *stats; 924 + unsigned long states; 925 + int var; 926 + 927 + if (cdev->ops->get_max_state(cdev, &states)) 928 + return; 929 + 930 + states++; /* Total number of states is highest state + 1 */ 931 + 932 + var = sizeof(*stats); 933 + var += sizeof(*stats->time_in_state) * states; 934 + var += sizeof(*stats->trans_table) * states * states; 935 + 936 + stats = kzalloc(var, GFP_KERNEL); 937 + if (!stats) 938 + return; 939 + 940 + stats->time_in_state = (ktime_t *)(stats + 1); 941 + stats->trans_table = (unsigned int *)(stats->time_in_state + states); 942 + cdev->stats = stats; 943 + stats->last_time = ktime_get(); 944 + stats->max_states = states; 945 + 946 + spin_lock_init(&stats->lock); 947 + 948 + /* Fill the empty slot left in cooling_device_attr_groups */ 949 + var = ARRAY_SIZE(cooling_device_attr_groups) - 2; 950 + cooling_device_attr_groups[var] = &cooling_device_stats_attr_group; 951 + } 952 + 953 + static void cooling_device_stats_destroy(struct thermal_cooling_device *cdev) 954 + { 955 + kfree(cdev->stats); 956 + cdev->stats = NULL; 957 + } 958 + 959 + #else 960 + 961 + static inline void 962 + cooling_device_stats_setup(struct thermal_cooling_device *cdev) {} 963 + static inline void 964 + cooling_device_stats_destroy(struct thermal_cooling_device *cdev) {} 965 + 966 + #endif /* CONFIG_THERMAL_STATISTICS */ 967 + 753 968 void thermal_cooling_device_setup_sysfs(struct thermal_cooling_device *cdev) 754 969 { 970 + cooling_device_stats_setup(cdev); 755 971 cdev->device.groups = cooling_device_attr_groups; 972 + } 973 + 974 + void thermal_cooling_device_destroy_sysfs(struct thermal_cooling_device *cdev) 975 + { 976 + cooling_device_stats_destroy(cdev); 756 977 } 757 978 758 979 /* these helper will be used only at the time of bindig */
+1
include/linux/thermal.h
··· 148 148 struct device device; 149 149 struct device_node *np; 150 150 void *devdata; 151 + void *stats; 151 152 const struct thermal_cooling_device_ops *ops; 152 153 bool updated; /* true if the cooling device does not need update */ 153 154 struct mutex lock; /* protect thermal_instances list */