aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/thermal/thermal_sys.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/thermal/thermal_sys.c')
-rw-r--r--drivers/thermal/thermal_sys.c356
1 files changed, 341 insertions, 15 deletions
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 8171ca17b936..d0b093b66adc 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -30,6 +30,7 @@
30#include <linux/idr.h> 30#include <linux/idr.h>
31#include <linux/thermal.h> 31#include <linux/thermal.h>
32#include <linux/spinlock.h> 32#include <linux/spinlock.h>
33#include <linux/reboot.h>
33 34
34MODULE_AUTHOR("Zhang Rui"); 35MODULE_AUTHOR("Zhang Rui");
35MODULE_DESCRIPTION("Generic thermal management sysfs support"); 36MODULE_DESCRIPTION("Generic thermal management sysfs support");
@@ -104,22 +105,36 @@ static ssize_t
104temp_show(struct device *dev, struct device_attribute *attr, char *buf) 105temp_show(struct device *dev, struct device_attribute *attr, char *buf)
105{ 106{
106 struct thermal_zone_device *tz = to_thermal_zone(dev); 107 struct thermal_zone_device *tz = to_thermal_zone(dev);
108 long temperature;
109 int ret;
107 110
108 if (!tz->ops->get_temp) 111 if (!tz->ops->get_temp)
109 return -EPERM; 112 return -EPERM;
110 113
111 return tz->ops->get_temp(tz, buf); 114 ret = tz->ops->get_temp(tz, &temperature);
115
116 if (ret)
117 return ret;
118
119 return sprintf(buf, "%ld\n", temperature);
112} 120}
113 121
114static ssize_t 122static ssize_t
115mode_show(struct device *dev, struct device_attribute *attr, char *buf) 123mode_show(struct device *dev, struct device_attribute *attr, char *buf)
116{ 124{
117 struct thermal_zone_device *tz = to_thermal_zone(dev); 125 struct thermal_zone_device *tz = to_thermal_zone(dev);
126 enum thermal_device_mode mode;
127 int result;
118 128
119 if (!tz->ops->get_mode) 129 if (!tz->ops->get_mode)
120 return -EPERM; 130 return -EPERM;
121 131
122 return tz->ops->get_mode(tz, buf); 132 result = tz->ops->get_mode(tz, &mode);
133 if (result)
134 return result;
135
136 return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
137 : "disabled");
123} 138}
124 139
125static ssize_t 140static ssize_t
@@ -132,7 +147,13 @@ mode_store(struct device *dev, struct device_attribute *attr,
132 if (!tz->ops->set_mode) 147 if (!tz->ops->set_mode)
133 return -EPERM; 148 return -EPERM;
134 149
135 result = tz->ops->set_mode(tz, buf); 150 if (!strncmp(buf, "enabled", sizeof("enabled")))
151 result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
152 else if (!strncmp(buf, "disabled", sizeof("disabled")))
153 result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
154 else
155 result = -EINVAL;
156
136 if (result) 157 if (result)
137 return result; 158 return result;
138 159
@@ -144,7 +165,8 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
144 char *buf) 165 char *buf)
145{ 166{
146 struct thermal_zone_device *tz = to_thermal_zone(dev); 167 struct thermal_zone_device *tz = to_thermal_zone(dev);
147 int trip; 168 enum thermal_trip_type type;
169 int trip, result;
148 170
149 if (!tz->ops->get_trip_type) 171 if (!tz->ops->get_trip_type)
150 return -EPERM; 172 return -EPERM;
@@ -152,7 +174,22 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
152 if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip)) 174 if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
153 return -EINVAL; 175 return -EINVAL;
154 176
155 return tz->ops->get_trip_type(tz, trip, buf); 177 result = tz->ops->get_trip_type(tz, trip, &type);
178 if (result)
179 return result;
180
181 switch (type) {
182 case THERMAL_TRIP_CRITICAL:
183 return sprintf(buf, "critical");
184 case THERMAL_TRIP_HOT:
185 return sprintf(buf, "hot");
186 case THERMAL_TRIP_PASSIVE:
187 return sprintf(buf, "passive");
188 case THERMAL_TRIP_ACTIVE:
189 return sprintf(buf, "active");
190 default:
191 return sprintf(buf, "unknown");
192 }
156} 193}
157 194
158static ssize_t 195static ssize_t
@@ -160,7 +197,8 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
160 char *buf) 197 char *buf)
161{ 198{
162 struct thermal_zone_device *tz = to_thermal_zone(dev); 199 struct thermal_zone_device *tz = to_thermal_zone(dev);
163 int trip; 200 int trip, ret;
201 long temperature;
164 202
165 if (!tz->ops->get_trip_temp) 203 if (!tz->ops->get_trip_temp)
166 return -EPERM; 204 return -EPERM;
@@ -168,12 +206,77 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
168 if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip)) 206 if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
169 return -EINVAL; 207 return -EINVAL;
170 208
171 return tz->ops->get_trip_temp(tz, trip, buf); 209 ret = tz->ops->get_trip_temp(tz, trip, &temperature);
210
211 if (ret)
212 return ret;
213
214 return sprintf(buf, "%ld\n", temperature);
215}
216
217static ssize_t
218passive_store(struct device *dev, struct device_attribute *attr,
219 const char *buf, size_t count)
220{
221 struct thermal_zone_device *tz = to_thermal_zone(dev);
222 struct thermal_cooling_device *cdev = NULL;
223 int state;
224
225 if (!sscanf(buf, "%d\n", &state))
226 return -EINVAL;
227
228 if (state && !tz->forced_passive) {
229 mutex_lock(&thermal_list_lock);
230 list_for_each_entry(cdev, &thermal_cdev_list, node) {
231 if (!strncmp("Processor", cdev->type,
232 sizeof("Processor")))
233 thermal_zone_bind_cooling_device(tz,
234 THERMAL_TRIPS_NONE,
235 cdev);
236 }
237 mutex_unlock(&thermal_list_lock);
238 } else if (!state && tz->forced_passive) {
239 mutex_lock(&thermal_list_lock);
240 list_for_each_entry(cdev, &thermal_cdev_list, node) {
241 if (!strncmp("Processor", cdev->type,
242 sizeof("Processor")))
243 thermal_zone_unbind_cooling_device(tz,
244 THERMAL_TRIPS_NONE,
245 cdev);
246 }
247 mutex_unlock(&thermal_list_lock);
248 }
249
250 tz->tc1 = 1;
251 tz->tc2 = 1;
252
253 if (!tz->passive_delay)
254 tz->passive_delay = 1000;
255
256 if (!tz->polling_delay)
257 tz->polling_delay = 10000;
258
259 tz->forced_passive = state;
260
261 thermal_zone_device_update(tz);
262
263 return count;
264}
265
266static ssize_t
267passive_show(struct device *dev, struct device_attribute *attr,
268 char *buf)
269{
270 struct thermal_zone_device *tz = to_thermal_zone(dev);
271
272 return sprintf(buf, "%d\n", tz->forced_passive);
172} 273}
173 274
174static DEVICE_ATTR(type, 0444, type_show, NULL); 275static DEVICE_ATTR(type, 0444, type_show, NULL);
175static DEVICE_ATTR(temp, 0444, temp_show, NULL); 276static DEVICE_ATTR(temp, 0444, temp_show, NULL);
176static DEVICE_ATTR(mode, 0644, mode_show, mode_store); 277static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
278static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, \
279 passive_store);
177 280
178static struct device_attribute trip_point_attrs[] = { 281static struct device_attribute trip_point_attrs[] = {
179 __ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL), 282 __ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL),
@@ -236,8 +339,13 @@ thermal_cooling_device_max_state_show(struct device *dev,
236 struct device_attribute *attr, char *buf) 339 struct device_attribute *attr, char *buf)
237{ 340{
238 struct thermal_cooling_device *cdev = to_cooling_device(dev); 341 struct thermal_cooling_device *cdev = to_cooling_device(dev);
342 unsigned long state;
343 int ret;
239 344
240 return cdev->ops->get_max_state(cdev, buf); 345 ret = cdev->ops->get_max_state(cdev, &state);
346 if (ret)
347 return ret;
348 return sprintf(buf, "%ld\n", state);
241} 349}
242 350
243static ssize_t 351static ssize_t
@@ -245,8 +353,13 @@ thermal_cooling_device_cur_state_show(struct device *dev,
245 struct device_attribute *attr, char *buf) 353 struct device_attribute *attr, char *buf)
246{ 354{
247 struct thermal_cooling_device *cdev = to_cooling_device(dev); 355 struct thermal_cooling_device *cdev = to_cooling_device(dev);
356 unsigned long state;
357 int ret;
248 358
249 return cdev->ops->get_cur_state(cdev, buf); 359 ret = cdev->ops->get_cur_state(cdev, &state);
360 if (ret)
361 return ret;
362 return sprintf(buf, "%ld\n", state);
250} 363}
251 364
252static ssize_t 365static ssize_t
@@ -255,10 +368,10 @@ thermal_cooling_device_cur_state_store(struct device *dev,
255 const char *buf, size_t count) 368 const char *buf, size_t count)
256{ 369{
257 struct thermal_cooling_device *cdev = to_cooling_device(dev); 370 struct thermal_cooling_device *cdev = to_cooling_device(dev);
258 int state; 371 unsigned long state;
259 int result; 372 int result;
260 373
261 if (!sscanf(buf, "%d\n", &state)) 374 if (!sscanf(buf, "%ld\n", &state))
262 return -EINVAL; 375 return -EINVAL;
263 376
264 if (state < 0) 377 if (state < 0)
@@ -312,13 +425,20 @@ static DEVICE_ATTR(name, 0444, name_show, NULL);
312static ssize_t 425static ssize_t
313temp_input_show(struct device *dev, struct device_attribute *attr, char *buf) 426temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
314{ 427{
428 long temperature;
429 int ret;
315 struct thermal_hwmon_attr *hwmon_attr 430 struct thermal_hwmon_attr *hwmon_attr
316 = container_of(attr, struct thermal_hwmon_attr, attr); 431 = container_of(attr, struct thermal_hwmon_attr, attr);
317 struct thermal_zone_device *tz 432 struct thermal_zone_device *tz
318 = container_of(hwmon_attr, struct thermal_zone_device, 433 = container_of(hwmon_attr, struct thermal_zone_device,
319 temp_input); 434 temp_input);
320 435
321 return tz->ops->get_temp(tz, buf); 436 ret = tz->ops->get_temp(tz, &temperature);
437
438 if (ret)
439 return ret;
440
441 return sprintf(buf, "%ld\n", temperature);
322} 442}
323 443
324static ssize_t 444static ssize_t
@@ -330,8 +450,14 @@ temp_crit_show(struct device *dev, struct device_attribute *attr,
330 struct thermal_zone_device *tz 450 struct thermal_zone_device *tz
331 = container_of(hwmon_attr, struct thermal_zone_device, 451 = container_of(hwmon_attr, struct thermal_zone_device,
332 temp_crit); 452 temp_crit);
453 long temperature;
454 int ret;
455
456 ret = tz->ops->get_trip_temp(tz, 0, &temperature);
457 if (ret)
458 return ret;
333 459
334 return tz->ops->get_trip_temp(tz, 0, buf); 460 return sprintf(buf, "%ld\n", temperature);
335} 461}
336 462
337 463
@@ -452,6 +578,97 @@ thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
452} 578}
453#endif 579#endif
454 580
581static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
582 int delay)
583{
584 cancel_delayed_work(&(tz->poll_queue));
585
586 if (!delay)
587 return;
588
589 if (delay > 1000)
590 schedule_delayed_work(&(tz->poll_queue),
591 round_jiffies(msecs_to_jiffies(delay)));
592 else
593 schedule_delayed_work(&(tz->poll_queue),
594 msecs_to_jiffies(delay));
595}
596
597static void thermal_zone_device_passive(struct thermal_zone_device *tz,
598 int temp, int trip_temp, int trip)
599{
600 int trend = 0;
601 struct thermal_cooling_device_instance *instance;
602 struct thermal_cooling_device *cdev;
603 long state, max_state;
604
605 /*
606 * Above Trip?
607 * -----------
608 * Calculate the thermal trend (using the passive cooling equation)
609 * and modify the performance limit for all passive cooling devices
610 * accordingly. Note that we assume symmetry.
611 */
612 if (temp >= trip_temp) {
613 tz->passive = true;
614
615 trend = (tz->tc1 * (temp - tz->last_temperature)) +
616 (tz->tc2 * (temp - trip_temp));
617
618 /* Heating up? */
619 if (trend > 0) {
620 list_for_each_entry(instance, &tz->cooling_devices,
621 node) {
622 if (instance->trip != trip)
623 continue;
624 cdev = instance->cdev;
625 cdev->ops->get_cur_state(cdev, &state);
626 cdev->ops->get_max_state(cdev, &max_state);
627 if (state++ < max_state)
628 cdev->ops->set_cur_state(cdev, state);
629 }
630 } else if (trend < 0) { /* Cooling off? */
631 list_for_each_entry(instance, &tz->cooling_devices,
632 node) {
633 if (instance->trip != trip)
634 continue;
635 cdev = instance->cdev;
636 cdev->ops->get_cur_state(cdev, &state);
637 cdev->ops->get_max_state(cdev, &max_state);
638 if (state > 0)
639 cdev->ops->set_cur_state(cdev, --state);
640 }
641 }
642 return;
643 }
644
645 /*
646 * Below Trip?
647 * -----------
648 * Implement passive cooling hysteresis to slowly increase performance
649 * and avoid thrashing around the passive trip point. Note that we
650 * assume symmetry.
651 */
652 list_for_each_entry(instance, &tz->cooling_devices, node) {
653 if (instance->trip != trip)
654 continue;
655 cdev = instance->cdev;
656 cdev->ops->get_cur_state(cdev, &state);
657 cdev->ops->get_max_state(cdev, &max_state);
658 if (state > 0)
659 cdev->ops->set_cur_state(cdev, --state);
660 if (state == 0)
661 tz->passive = false;
662 }
663}
664
665static void thermal_zone_device_check(struct work_struct *work)
666{
667 struct thermal_zone_device *tz = container_of(work, struct
668 thermal_zone_device,
669 poll_queue.work);
670 thermal_zone_device_update(tz);
671}
455 672
456/** 673/**
457 * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone 674 * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
@@ -722,25 +939,113 @@ void thermal_cooling_device_unregister(struct
722EXPORT_SYMBOL(thermal_cooling_device_unregister); 939EXPORT_SYMBOL(thermal_cooling_device_unregister);
723 940
724/** 941/**
942 * thermal_zone_device_update - force an update of a thermal zone's state
943 * @ttz: the thermal zone to update
944 */
945
946void thermal_zone_device_update(struct thermal_zone_device *tz)
947{
948 int count, ret = 0;
949 long temp, trip_temp;
950 enum thermal_trip_type trip_type;
951 struct thermal_cooling_device_instance *instance;
952 struct thermal_cooling_device *cdev;
953
954 mutex_lock(&tz->lock);
955
956 tz->ops->get_temp(tz, &temp);
957
958 for (count = 0; count < tz->trips; count++) {
959 tz->ops->get_trip_type(tz, count, &trip_type);
960 tz->ops->get_trip_temp(tz, count, &trip_temp);
961
962 switch (trip_type) {
963 case THERMAL_TRIP_CRITICAL:
964 if (temp > trip_temp) {
965 if (tz->ops->notify)
966 ret = tz->ops->notify(tz, count,
967 trip_type);
968 if (!ret) {
969 printk(KERN_EMERG
970 "Critical temperature reached (%ld C), shutting down.\n",
971 temp/1000);
972 orderly_poweroff(true);
973 }
974 }
975 break;
976 case THERMAL_TRIP_HOT:
977 if (temp > trip_temp)
978 if (tz->ops->notify)
979 tz->ops->notify(tz, count, trip_type);
980 break;
981 case THERMAL_TRIP_ACTIVE:
982 list_for_each_entry(instance, &tz->cooling_devices,
983 node) {
984 if (instance->trip != count)
985 continue;
986
987 cdev = instance->cdev;
988
989 if (temp > trip_temp)
990 cdev->ops->set_cur_state(cdev, 1);
991 else
992 cdev->ops->set_cur_state(cdev, 0);
993 }
994 break;
995 case THERMAL_TRIP_PASSIVE:
996 if (temp > trip_temp || tz->passive)
997 thermal_zone_device_passive(tz, temp,
998 trip_temp, count);
999 break;
1000 }
1001 }
1002
1003 if (tz->forced_passive)
1004 thermal_zone_device_passive(tz, temp, tz->forced_passive,
1005 THERMAL_TRIPS_NONE);
1006
1007 tz->last_temperature = temp;
1008 if (tz->passive)
1009 thermal_zone_device_set_polling(tz, tz->passive_delay);
1010 else if (tz->polling_delay)
1011 thermal_zone_device_set_polling(tz, tz->polling_delay);
1012 mutex_unlock(&tz->lock);
1013}
1014EXPORT_SYMBOL(thermal_zone_device_update);
1015
1016/**
725 * thermal_zone_device_register - register a new thermal zone device 1017 * thermal_zone_device_register - register a new thermal zone device
726 * @type: the thermal zone device type 1018 * @type: the thermal zone device type
727 * @trips: the number of trip points the thermal zone support 1019 * @trips: the number of trip points the thermal zone support
728 * @devdata: private device data 1020 * @devdata: private device data
729 * @ops: standard thermal zone device callbacks 1021 * @ops: standard thermal zone device callbacks
1022 * @tc1: thermal coefficient 1 for passive calculations
1023 * @tc2: thermal coefficient 2 for passive calculations
1024 * @passive_delay: number of milliseconds to wait between polls when
1025 * performing passive cooling
1026 * @polling_delay: number of milliseconds to wait between polls when checking
1027 * whether trip points have been crossed (0 for interrupt
1028 * driven systems)
730 * 1029 *
731 * thermal_zone_device_unregister() must be called when the device is no 1030 * thermal_zone_device_unregister() must be called when the device is no
732 * longer needed. 1031 * longer needed. The passive cooling formula uses tc1 and tc2 as described in
1032 * section 11.1.5.1 of the ACPI specification 3.0.
733 */ 1033 */
734struct thermal_zone_device *thermal_zone_device_register(char *type, 1034struct thermal_zone_device *thermal_zone_device_register(char *type,
735 int trips, 1035 int trips,
736 void *devdata, struct 1036 void *devdata, struct
737 thermal_zone_device_ops 1037 thermal_zone_device_ops
738 *ops) 1038 *ops, int tc1, int
1039 tc2,
1040 int passive_delay,
1041 int polling_delay)
739{ 1042{
740 struct thermal_zone_device *tz; 1043 struct thermal_zone_device *tz;
741 struct thermal_cooling_device *pos; 1044 struct thermal_cooling_device *pos;
1045 enum thermal_trip_type trip_type;
742 int result; 1046 int result;
743 int count; 1047 int count;
1048 int passive = 0;
744 1049
745 if (strlen(type) >= THERMAL_NAME_LENGTH) 1050 if (strlen(type) >= THERMAL_NAME_LENGTH)
746 return ERR_PTR(-EINVAL); 1051 return ERR_PTR(-EINVAL);
@@ -769,6 +1074,11 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
769 tz->device.class = &thermal_class; 1074 tz->device.class = &thermal_class;
770 tz->devdata = devdata; 1075 tz->devdata = devdata;
771 tz->trips = trips; 1076 tz->trips = trips;
1077 tz->tc1 = tc1;
1078 tz->tc2 = tc2;
1079 tz->passive_delay = passive_delay;
1080 tz->polling_delay = polling_delay;
1081
772 dev_set_name(&tz->device, "thermal_zone%d", tz->id); 1082 dev_set_name(&tz->device, "thermal_zone%d", tz->id);
773 result = device_register(&tz->device); 1083 result = device_register(&tz->device);
774 if (result) { 1084 if (result) {
@@ -798,8 +1108,18 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
798 TRIP_POINT_ATTR_ADD(&tz->device, count, result); 1108 TRIP_POINT_ATTR_ADD(&tz->device, count, result);
799 if (result) 1109 if (result)
800 goto unregister; 1110 goto unregister;
1111 tz->ops->get_trip_type(tz, count, &trip_type);
1112 if (trip_type == THERMAL_TRIP_PASSIVE)
1113 passive = 1;
801 } 1114 }
802 1115
1116 if (!passive)
1117 result = device_create_file(&tz->device,
1118 &dev_attr_passive);
1119
1120 if (result)
1121 goto unregister;
1122
803 result = thermal_add_hwmon_sysfs(tz); 1123 result = thermal_add_hwmon_sysfs(tz);
804 if (result) 1124 if (result)
805 goto unregister; 1125 goto unregister;
@@ -814,6 +1134,10 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
814 } 1134 }
815 mutex_unlock(&thermal_list_lock); 1135 mutex_unlock(&thermal_list_lock);
816 1136
1137 INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
1138
1139 thermal_zone_device_update(tz);
1140
817 if (!result) 1141 if (!result)
818 return tz; 1142 return tz;
819 1143
@@ -853,6 +1177,8 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
853 tz->ops->unbind(tz, cdev); 1177 tz->ops->unbind(tz, cdev);
854 mutex_unlock(&thermal_list_lock); 1178 mutex_unlock(&thermal_list_lock);
855 1179
1180 thermal_zone_device_set_polling(tz, 0);
1181
856 if (tz->type[0]) 1182 if (tz->type[0])
857 device_remove_file(&tz->device, &dev_attr_type); 1183 device_remove_file(&tz->device, &dev_attr_type);
858 device_remove_file(&tz->device, &dev_attr_temp); 1184 device_remove_file(&tz->device, &dev_attr_temp);