aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Garrett <mjg59@srcf.ucam.org>2008-12-03 13:00:38 -0500
committerLen Brown <len.brown@intel.com>2009-03-27 16:58:22 -0400
commit03a971a2899886006f19f3495973bbd646d8bdae (patch)
tree6b82e8d67ca5eaf94fce4bd419276d90ac281c8e
parentf6f5c45e06e86d94621cd5c1c4508bdee1952fc8 (diff)
thermal: support forcing support for passive cooling
Due to poor thermal design or Linux driving hardware outside its thermal envelope, some systems will reach critical temperature and shut down under high load. This patch adds support for forcing a polling-based passive trip point if the firmware doesn't provide one. The assumption is made that the processor is the most practical means to reduce the dynamic heat generation, so hitting the passive thermal limit will cause the CPU to be throttled until the temperature stabalises around the defined value. UI is provided via a "passive" sysfs entry in the thermal zone directory. It accepts a decimal value in millidegrees celsius, or "0" to disable the functionality. Default behaviour is for this functionality to be disabled. Signed-off-by: Matthew Garrett <mjg@redhat.com> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--drivers/thermal/thermal_sys.c77
-rw-r--r--include/linux/thermal.h1
2 files changed, 78 insertions, 0 deletions
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 6378741882f3..d0b093b66adc 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -214,9 +214,69 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
214 return sprintf(buf, "%ld\n", temperature); 214 return sprintf(buf, "%ld\n", temperature);
215} 215}
216 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);
273}
274
217static DEVICE_ATTR(type, 0444, type_show, NULL); 275static DEVICE_ATTR(type, 0444, type_show, NULL);
218static DEVICE_ATTR(temp, 0444, temp_show, NULL); 276static DEVICE_ATTR(temp, 0444, temp_show, NULL);
219static 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);
220 280
221static struct device_attribute trip_point_attrs[] = { 281static struct device_attribute trip_point_attrs[] = {
222 __ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL), 282 __ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL),
@@ -939,6 +999,11 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
939 break; 999 break;
940 } 1000 }
941 } 1001 }
1002
1003 if (tz->forced_passive)
1004 thermal_zone_device_passive(tz, temp, tz->forced_passive,
1005 THERMAL_TRIPS_NONE);
1006
942 tz->last_temperature = temp; 1007 tz->last_temperature = temp;
943 if (tz->passive) 1008 if (tz->passive)
944 thermal_zone_device_set_polling(tz, tz->passive_delay); 1009 thermal_zone_device_set_polling(tz, tz->passive_delay);
@@ -977,8 +1042,10 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
977{ 1042{
978 struct thermal_zone_device *tz; 1043 struct thermal_zone_device *tz;
979 struct thermal_cooling_device *pos; 1044 struct thermal_cooling_device *pos;
1045 enum thermal_trip_type trip_type;
980 int result; 1046 int result;
981 int count; 1047 int count;
1048 int passive = 0;
982 1049
983 if (strlen(type) >= THERMAL_NAME_LENGTH) 1050 if (strlen(type) >= THERMAL_NAME_LENGTH)
984 return ERR_PTR(-EINVAL); 1051 return ERR_PTR(-EINVAL);
@@ -1041,8 +1108,18 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
1041 TRIP_POINT_ATTR_ADD(&tz->device, count, result); 1108 TRIP_POINT_ATTR_ADD(&tz->device, count, result);
1042 if (result) 1109 if (result)
1043 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;
1044 } 1114 }
1045 1115
1116 if (!passive)
1117 result = device_create_file(&tz->device,
1118 &dev_attr_passive);
1119
1120 if (result)
1121 goto unregister;
1122
1046 result = thermal_add_hwmon_sysfs(tz); 1123 result = thermal_add_hwmon_sysfs(tz);
1047 if (result) 1124 if (result)
1048 goto unregister; 1125 goto unregister;
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index a81c61521ba4..1de8b9eb841b 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -113,6 +113,7 @@ struct thermal_zone_device {
113 int polling_delay; 113 int polling_delay;
114 int last_temperature; 114 int last_temperature;
115 bool passive; 115 bool passive;
116 unsigned int forced_passive;
116 struct thermal_zone_device_ops *ops; 117 struct thermal_zone_device_ops *ops;
117 struct list_head cooling_devices; 118 struct list_head cooling_devices;
118 struct idr idr; 119 struct idr idr;