Merge a fix for a recent thermal-related regression in the ACPI processor driver. * thermal-acpi: ACPI: processor: thermal: Update CPU cooling devices on cpufreq policy changes thermal: core: Introduce thermal_cooling_device_update() thermal: core: Introduce thermal_cooling_device_present() ACPI: processor: Reorder acpi_processor_driver_init()
Unified · Split
| @@ -263,6 +263,12 @@ static int __init acpi_processor_driver_init(void) · 262 unmodified lines | ||
| 263 | 263 | if (acpi_disabled) |
| 264 | 264 | return 0; |
| 265 | 265 | |
| 266 | + if (!cpufreq_register_notifier(&acpi_processor_notifier_block, | |
| 267 | + CPUFREQ_POLICY_NOTIFIER)) { | |
| 268 | + acpi_processor_cpufreq_init = true; | |
| 269 | + acpi_processor_ignore_ppc_init(); | |
| 270 | + } | |
| 271 | + | |
| 266 | 272 | result = driver_register(&acpi_processor_driver); |
| 267 | 273 | if (result < 0) |
| 268 | 274 | return result; |
| @@ -276,12 +282,6 @@ static int __init acpi_processor_driver_init(void) · 7 unmodified lines | ||
| 276 | 282 | cpuhp_setup_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD, "acpi/cpu-drv:dead", |
| 277 | 283 | NULL, acpi_soft_cpu_dead); |
| 278 | 284 | |
| 279 | − if (!cpufreq_register_notifier(&acpi_processor_notifier_block, | |
| 280 | − CPUFREQ_POLICY_NOTIFIER)) { | |
| 281 | − acpi_processor_cpufreq_init = true; | |
| 282 | − acpi_processor_ignore_ppc_init(); | |
| 283 | − } | |
| 284 | − | |
| 285 | 285 | acpi_processor_throttling_init(); |
| 286 | 286 | return 0; |
| 287 | 287 | err: |
| @@ -140,9 +140,13 @@ void acpi_thermal_cpufreq_init(struct cpufreq_policy *policy) · 139 unmodified lines | ||
| 140 | 140 | ret = freq_qos_add_request(&policy->constraints, |
| 141 | 141 | &pr->thermal_req, |
| 142 | 142 | FREQ_QOS_MAX, INT_MAX); |
| 143 | − if (ret < 0) | |
| 143 | + if (ret < 0) { | |
| 144 | 144 | pr_err("Failed to add freq constraint for CPU%d (%d)\n", |
| 145 | 145 | cpu, ret); |
| 146 | + continue; | |
| 147 | + } | |
| 148 | + | |
| 149 | + thermal_cooling_device_update(pr->cdev); | |
| 146 | 150 | } |
| 147 | 151 | } |
| 148 | 152 | |
| @@ -153,8 +157,12 @@ void acpi_thermal_cpufreq_exit(struct cpufreq_policy *policy) · 4 unmodified lines | ||
| 153 | 157 | for_each_cpu(cpu, policy->related_cpus) { |
| 154 | 158 | struct acpi_processor *pr = per_cpu(processors, cpu); |
| 155 | 159 | |
| 156 | − if (pr) | |
| 157 | − freq_qos_remove_request(&pr->thermal_req); | |
| 160 | + if (!pr) | |
| 161 | + continue; | |
| 162 | + | |
| 163 | + freq_qos_remove_request(&pr->thermal_req); | |
| 164 | + | |
| 165 | + thermal_cooling_device_update(pr->cdev); | |
| 158 | 166 | } |
| 159 | 167 | } |
| 160 | 168 | #else /* ! CONFIG_CPU_FREQ */ |
| @@ -613,6 +613,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, · 612 unmodified lines | ||
| 613 | 613 | struct thermal_instance *pos; |
| 614 | 614 | struct thermal_zone_device *pos1; |
| 615 | 615 | struct thermal_cooling_device *pos2; |
| 616 | + bool upper_no_limit; | |
| 616 | 617 | int result; |
| 617 | 618 | |
| 618 | 619 | if (trip >= tz->num_trips || trip < 0) |
| @@ -632,7 +633,13 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, · 13 unmodified lines | ||
| 632 | 633 | |
| 633 | 634 | /* lower default 0, upper default max_state */ |
| 634 | 635 | lower = lower == THERMAL_NO_LIMIT ? 0 : lower; |
| 635 | − upper = upper == THERMAL_NO_LIMIT ? cdev->max_state : upper; | |
| 636 | + | |
| 637 | + if (upper == THERMAL_NO_LIMIT) { | |
| 638 | + upper = cdev->max_state; | |
| 639 | + upper_no_limit = true; | |
| 640 | + } else { | |
| 641 | + upper_no_limit = false; | |
| 642 | + } | |
| 636 | 643 | |
| 637 | 644 | if (lower > upper || upper > cdev->max_state) |
| 638 | 645 | return -EINVAL; |
| @@ -644,6 +651,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, · 5 unmodified lines | ||
| 644 | 651 | dev->cdev = cdev; |
| 645 | 652 | dev->trip = trip; |
| 646 | 653 | dev->upper = upper; |
| 654 | + dev->upper_no_limit = upper_no_limit; | |
| 647 | 655 | dev->lower = lower; |
| 648 | 656 | dev->target = THERMAL_NO_TARGET; |
| 649 | 657 | dev->weight = weight; |
| @@ -1045,6 +1053,91 @@ devm_thermal_of_cooling_device_register(struct device *dev, · 395 unmodified lines | ||
| 1045 | 1053 | } |
| 1046 | 1054 | EXPORT_SYMBOL_GPL(devm_thermal_of_cooling_device_register); |
| 1047 | 1055 | |
| 1056 | +static bool thermal_cooling_device_present(struct thermal_cooling_device *cdev) | |
| 1057 | +{ | |
| 1058 | + struct thermal_cooling_device *pos = NULL; | |
| 1059 | + | |
| 1060 | + list_for_each_entry(pos, &thermal_cdev_list, node) { | |
| 1061 | + if (pos == cdev) | |
| 1062 | + return true; | |
| 1063 | + } | |
| 1064 | + | |
| 1065 | + return false; | |
| 1066 | +} | |
| 1067 | + | |
| 1068 | +/** | |
| 1069 | + * thermal_cooling_device_update - Update a cooling device object | |
| 1070 | + * @cdev: Target cooling device. | |
| 1071 | + * | |
| 1072 | + * Update @cdev to reflect a change of the underlying hardware or platform. | |
| 1073 | + * | |
| 1074 | + * Must be called when the maximum cooling state of @cdev becomes invalid and so | |
| 1075 | + * its .get_max_state() callback needs to be run to produce the new maximum | |
| 1076 | + * cooling state value. | |
| 1077 | + */ | |
| 1078 | +void thermal_cooling_device_update(struct thermal_cooling_device *cdev) | |
| 1079 | +{ | |
| 1080 | + struct thermal_instance *ti; | |
| 1081 | + unsigned long state; | |
| 1082 | + | |
| 1083 | + if (IS_ERR_OR_NULL(cdev)) | |
| 1084 | + return; | |
| 1085 | + | |
| 1086 | + /* | |
| 1087 | + * Hold thermal_list_lock throughout the update to prevent the device | |
| 1088 | + * from going away while being updated. | |
| 1089 | + */ | |
| 1090 | + mutex_lock(&thermal_list_lock); | |
| 1091 | + | |
| 1092 | + if (!thermal_cooling_device_present(cdev)) | |
| 1093 | + goto unlock_list; | |
| 1094 | + | |
| 1095 | + /* | |
| 1096 | + * Update under the cdev lock to prevent the state from being set beyond | |
| 1097 | + * the new limit concurrently. | |
| 1098 | + */ | |
| 1099 | + mutex_lock(&cdev->lock); | |
| 1100 | + | |
| 1101 | + if (cdev->ops->get_max_state(cdev, &cdev->max_state)) | |
| 1102 | + goto unlock; | |
| 1103 | + | |
| 1104 | + thermal_cooling_device_stats_reinit(cdev); | |
| 1105 | + | |
| 1106 | + list_for_each_entry(ti, &cdev->thermal_instances, cdev_node) { | |
| 1107 | + if (ti->upper == cdev->max_state) | |
| 1108 | + continue; | |
| 1109 | + | |
| 1110 | + if (ti->upper < cdev->max_state) { | |
| 1111 | + if (ti->upper_no_limit) | |
| 1112 | + ti->upper = cdev->max_state; | |
| 1113 | + | |
| 1114 | + continue; | |
| 1115 | + } | |
| 1116 | + | |
| 1117 | + ti->upper = cdev->max_state; | |
| 1118 | + if (ti->lower > ti->upper) | |
| 1119 | + ti->lower = ti->upper; | |
| 1120 | + | |
| 1121 | + if (ti->target == THERMAL_NO_TARGET) | |
| 1122 | + continue; | |
| 1123 | + | |
| 1124 | + if (ti->target > ti->upper) | |
| 1125 | + ti->target = ti->upper; | |
| 1126 | + } | |
| 1127 | + | |
| 1128 | + if (cdev->ops->get_cur_state(cdev, &state) || state > cdev->max_state) | |
| 1129 | + goto unlock; | |
| 1130 | + | |
| 1131 | + thermal_cooling_device_stats_update(cdev, state); | |
| 1132 | + | |
| 1133 | +unlock: | |
| 1134 | + mutex_unlock(&cdev->lock); | |
| 1135 | + | |
| 1136 | +unlock_list: | |
| 1137 | + mutex_unlock(&thermal_list_lock); | |
| 1138 | +} | |
| 1139 | +EXPORT_SYMBOL_GPL(thermal_cooling_device_update); | |
| 1140 | + | |
| 1048 | 1141 | static void __unbind(struct thermal_zone_device *tz, int mask, |
| 1049 | 1142 | struct thermal_cooling_device *cdev) |
| 1050 | 1143 | { |
| @@ -1067,20 +1160,17 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev) · 16 unmodified lines | ||
| 1067 | 1160 | int i; |
| 1068 | 1161 | const struct thermal_zone_params *tzp; |
| 1069 | 1162 | struct thermal_zone_device *tz; |
| 1070 | − struct thermal_cooling_device *pos = NULL; | |
| 1071 | 1163 | |
| 1072 | 1164 | if (!cdev) |
| 1073 | 1165 | return; |
| 1074 | 1166 | |
| 1075 | 1167 | mutex_lock(&thermal_list_lock); |
| 1076 | − list_for_each_entry(pos, &thermal_cdev_list, node) | |
| 1077 | − if (pos == cdev) | |
| 1078 | − break; | |
| 1079 | − if (pos != cdev) { | |
| 1080 | − /* thermal cooling device not found */ | |
| 1168 | + | |
| 1169 | + if (!thermal_cooling_device_present(cdev)) { | |
| 1081 | 1170 | mutex_unlock(&thermal_list_lock); |
| 1082 | 1171 | return; |
| 1083 | 1172 | } |
| 1173 | + | |
| 1084 | 1174 | list_del(&cdev->node); |
| 1085 | 1175 | |
| 1086 | 1176 | /* Unbind all thermal zones associated with 'this' cdev */ |
| @@ -101,6 +101,7 @@ struct thermal_instance { · 100 unmodified lines | ||
| 101 | 101 | struct list_head tz_node; /* node in tz->thermal_instances */ |
| 102 | 102 | struct list_head cdev_node; /* node in cdev->thermal_instances */ |
| 103 | 103 | unsigned int weight; /* The weight of the cooling device */ |
| 104 | + bool upper_no_limit; | |
| 104 | 105 | }; |
| 105 | 106 | |
| 106 | 107 | #define to_thermal_zone(_dev) \ |
| @@ -127,6 +128,7 @@ int thermal_zone_create_device_groups(struct thermal_zone_device *, int); · 20 unmodified lines | ||
| 127 | 128 | void thermal_zone_destroy_device_groups(struct thermal_zone_device *); |
| 128 | 129 | void thermal_cooling_device_setup_sysfs(struct thermal_cooling_device *); |
| 129 | 130 | void thermal_cooling_device_destroy_sysfs(struct thermal_cooling_device *cdev); |
| 131 | +void thermal_cooling_device_stats_reinit(struct thermal_cooling_device *cdev); | |
| 130 | 132 | /* used only at binding time */ |
| 131 | 133 | ssize_t trip_point_show(struct device *, struct device_attribute *, char *); |
| 132 | 134 | ssize_t weight_show(struct device *, struct device_attribute *, char *); |
| @@ -685,6 +685,8 @@ void thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev, · 684 unmodified lines | ||
| 685 | 685 | { |
| 686 | 686 | struct cooling_dev_stats *stats = cdev->stats; |
| 687 | 687 | |
| 688 | + lockdep_assert_held(&cdev->lock); | |
| 689 | + | |
| 688 | 690 | if (!stats) |
| 689 | 691 | return; |
| 690 | 692 | |
| @@ -706,13 +708,22 @@ static ssize_t total_trans_show(struct device *dev, · 15 unmodified lines | ||
| 706 | 708 | struct device_attribute *attr, char *buf) |
| 707 | 709 | { |
| 708 | 710 | struct thermal_cooling_device *cdev = to_cooling_device(dev); |
| 709 | − struct cooling_dev_stats *stats = cdev->stats; | |
| 710 | − int ret; | |
| 711 | + struct cooling_dev_stats *stats; | |
| 712 | + int ret = 0; | |
| 713 | + | |
| 714 | + mutex_lock(&cdev->lock); | |
| 715 | + | |
| 716 | + stats = cdev->stats; | |
| 717 | + if (!stats) | |
| 718 | + goto unlock; | |
| 711 | 719 | |
| 712 | 720 | spin_lock(&stats->lock); |
| 713 | 721 | ret = sprintf(buf, "%u\n", stats->total_trans); |
| 714 | 722 | spin_unlock(&stats->lock); |
| 715 | 723 | |
| 724 | +unlock: | |
| 725 | + mutex_unlock(&cdev->lock); | |
| 726 | + | |
| 716 | 727 | return ret; |
| 717 | 728 | } |
| 718 | 729 | |
| @@ -721,11 +732,18 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr, · 2 unmodified lines | ||
| 721 | 732 | char *buf) |
| 722 | 733 | { |
| 723 | 734 | struct thermal_cooling_device *cdev = to_cooling_device(dev); |
| 724 | − struct cooling_dev_stats *stats = cdev->stats; | |
| 735 | + struct cooling_dev_stats *stats; | |
| 725 | 736 | ssize_t len = 0; |
| 726 | 737 | int i; |
| 727 | 738 | |
| 739 | + mutex_lock(&cdev->lock); | |
| 740 | + | |
| 741 | + stats = cdev->stats; | |
| 742 | + if (!stats) | |
| 743 | + goto unlock; | |
| 744 | + | |
| 728 | 745 | spin_lock(&stats->lock); |
| 746 | + | |
| 729 | 747 | update_time_in_state(stats); |
| 730 | 748 | |
| 731 | 749 | for (i = 0; i <= cdev->max_state; i++) { |
| @@ -734,6 +752,9 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr, · 2 unmodified lines | ||
| 734 | 752 | } |
| 735 | 753 | spin_unlock(&stats->lock); |
| 736 | 754 | |
| 755 | +unlock: | |
| 756 | + mutex_unlock(&cdev->lock); | |
| 757 | + | |
| 737 | 758 | return len; |
| 738 | 759 | } |
| 739 | 760 | |
| @@ -742,8 +763,16 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf, · 2 unmodified lines | ||
| 742 | 763 | size_t count) |
| 743 | 764 | { |
| 744 | 765 | struct thermal_cooling_device *cdev = to_cooling_device(dev); |
| 745 | − struct cooling_dev_stats *stats = cdev->stats; | |
| 746 | − int i, states = cdev->max_state + 1; | |
| 766 | + struct cooling_dev_stats *stats; | |
| 767 | + int i, states; | |
| 768 | + | |
| 769 | + mutex_lock(&cdev->lock); | |
| 770 | + | |
| 771 | + stats = cdev->stats; | |
| 772 | + if (!stats) | |
| 773 | + goto unlock; | |
| 774 | + | |
| 775 | + states = cdev->max_state + 1; | |
| 747 | 776 | |
| 748 | 777 | spin_lock(&stats->lock); |
| 749 | 778 | |
| @@ -757,6 +786,9 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf, · 7 unmodified lines | ||
| 757 | 786 | |
| 758 | 787 | spin_unlock(&stats->lock); |
| 759 | 788 | |
| 789 | +unlock: | |
| 790 | + mutex_unlock(&cdev->lock); | |
| 791 | + | |
| 760 | 792 | return count; |
| 761 | 793 | } |
| 762 | 794 | |
| @@ -764,10 +796,18 @@ static ssize_t trans_table_show(struct device *dev, · 1 unmodified line | ||
| 764 | 796 | struct device_attribute *attr, char *buf) |
| 765 | 797 | { |
| 766 | 798 | struct thermal_cooling_device *cdev = to_cooling_device(dev); |
| 767 | − struct cooling_dev_stats *stats = cdev->stats; | |
| 799 | + struct cooling_dev_stats *stats; | |
| 768 | 800 | ssize_t len = 0; |
| 769 | 801 | int i, j; |
| 770 | 802 | |
| 803 | + mutex_lock(&cdev->lock); | |
| 804 | + | |
| 805 | + stats = cdev->stats; | |
| 806 | + if (!stats) { | |
| 807 | + len = -ENODATA; | |
| 808 | + goto unlock; | |
| 809 | + } | |
| 810 | + | |
| 771 | 811 | len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n"); |
| 772 | 812 | len += snprintf(buf + len, PAGE_SIZE - len, " : "); |
| 773 | 813 | for (i = 0; i <= cdev->max_state; i++) { |
| @@ -775,8 +815,10 @@ static ssize_t trans_table_show(struct device *dev, · 1 unmodified line | ||
| 775 | 815 | break; |
| 776 | 816 | len += snprintf(buf + len, PAGE_SIZE - len, "state%2u ", i); |
| 777 | 817 | } |
| 778 | − if (len >= PAGE_SIZE) | |
| 779 | − return PAGE_SIZE; | |
| 818 | + if (len >= PAGE_SIZE) { | |
| 819 | + len = PAGE_SIZE; | |
| 820 | + goto unlock; | |
| 821 | + } | |
| 780 | 822 | |
| 781 | 823 | len += snprintf(buf + len, PAGE_SIZE - len, "\n"); |
| 782 | 824 | |
| @@ -799,8 +841,12 @@ static ssize_t trans_table_show(struct device *dev, · 16 unmodified lines | ||
| 799 | 841 | |
| 800 | 842 | if (len >= PAGE_SIZE) { |
| 801 | 843 | pr_warn_once("Thermal transition table exceeds PAGE_SIZE. Disabling\n"); |
| 802 | − return -EFBIG; | |
| 844 | + len = -EFBIG; | |
| 803 | 845 | } |
| 846 | + | |
| 847 | +unlock: | |
| 848 | + mutex_unlock(&cdev->lock); | |
| 849 | + | |
| 804 | 850 | return len; |
| 805 | 851 | } |
| 806 | 852 | |
| @@ -830,6 +876,8 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev) · 23 unmodified lines | ||
| 830 | 876 | unsigned long states = cdev->max_state + 1; |
| 831 | 877 | int var; |
| 832 | 878 | |
| 879 | + lockdep_assert_held(&cdev->lock); | |
| 880 | + | |
| 833 | 881 | var = sizeof(*stats); |
| 834 | 882 | var += sizeof(*stats->time_in_state) * states; |
| 835 | 883 | var += sizeof(*stats->trans_table) * states * states; |
| @@ -855,6 +903,8 @@ out: · 19 unmodified lines | ||
| 855 | 903 | |
| 856 | 904 | static void cooling_device_stats_destroy(struct thermal_cooling_device *cdev) |
| 857 | 905 | { |
| 906 | + lockdep_assert_held(&cdev->lock); | |
| 907 | + | |
| 858 | 908 | kfree(cdev->stats); |
| 859 | 909 | cdev->stats = NULL; |
| 860 | 910 | } |
| @@ -879,6 +929,12 @@ void thermal_cooling_device_destroy_sysfs(struct thermal_cooling_device *cdev) · 18 unmodified lines | ||
| 879 | 929 | cooling_device_stats_destroy(cdev); |
| 880 | 930 | } |
| 881 | 931 | |
| 932 | +void thermal_cooling_device_stats_reinit(struct thermal_cooling_device *cdev) | |
| 933 | +{ | |
| 934 | + cooling_device_stats_destroy(cdev); | |
| 935 | + cooling_device_stats_setup(cdev); | |
| 936 | +} | |
| 937 | + | |
| 882 | 938 | /* these helper will be used only at the time of bindig */ |
| 883 | 939 | ssize_t |
| 884 | 940 | trip_point_show(struct device *dev, struct device_attribute *attr, char *buf) |
| @@ -384,6 +384,7 @@ devm_thermal_of_cooling_device_register(struct device *dev, · 383 unmodified lines | ||
| 384 | 384 | struct device_node *np, |
| 385 | 385 | char *type, void *devdata, |
| 386 | 386 | const struct thermal_cooling_device_ops *ops); |
| 387 | +void thermal_cooling_device_update(struct thermal_cooling_device *); | |
| 387 | 388 | void thermal_cooling_device_unregister(struct thermal_cooling_device *); |
| 388 | 389 | struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name); |
| 389 | 390 | int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp); |