aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/thermal
diff options
context:
space:
mode:
authorZhang Rui <rui.zhang@intel.com>2012-06-27 02:13:04 -0400
committerZhang Rui <rui.zhang@intel.com>2012-09-24 02:44:37 -0400
commitce119f83257aae29b84a5bfad0669e8348437b18 (patch)
tree82ef036b21cc958beed8a0c7def6fbe50ab3ca1b /drivers/thermal
parentb5e4ae620b06274981781aeadc2aea50b507f7fb (diff)
Thermal: Introduce simple arbitrator for setting device cooling state
This fixes the problem that a cooling device may be referenced by by multiple trip points in multiple thermal zones. With this patch, we have two stages for updating a thermal zone, 1. check if a thermal_instance needs to be updated or not 2. update the cooling device, based on the target cooling state of all its instances. Note that, currently, the cooling device is set to the deepest cooling state required. Signed-off-by: Zhang Rui <rui.zhang@intel.com> Reviewed-by: Rafael J. Wysocki <rjw@sisk.pl> Reviewed-by: Eduardo Valentin <eduardo.valentin@ti.com>
Diffstat (limited to 'drivers/thermal')
-rw-r--r--drivers/thermal/thermal_sys.c44
1 files changed, 41 insertions, 3 deletions
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 70045c12d7df..36ae2f43ee2e 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -41,6 +41,7 @@ MODULE_AUTHOR("Zhang Rui");
41MODULE_DESCRIPTION("Generic thermal management sysfs support"); 41MODULE_DESCRIPTION("Generic thermal management sysfs support");
42MODULE_LICENSE("GPL"); 42MODULE_LICENSE("GPL");
43 43
44#define THERMAL_NO_TARGET -1UL
44/* 45/*
45 * This structure is used to describe the behavior of 46 * This structure is used to describe the behavior of
46 * a certain cooling device on a certain trip point 47 * a certain cooling device on a certain trip point
@@ -54,6 +55,7 @@ struct thermal_instance {
54 int trip; 55 int trip;
55 unsigned long upper; /* Highest cooling state for this trip point */ 56 unsigned long upper; /* Highest cooling state for this trip point */
56 unsigned long lower; /* Lowest cooling state for this trip point */ 57 unsigned long lower; /* Lowest cooling state for this trip point */
58 unsigned long target; /* expected cooling state */
57 char attr_name[THERMAL_NAME_LENGTH]; 59 char attr_name[THERMAL_NAME_LENGTH];
58 struct device_attribute attr; 60 struct device_attribute attr;
59 struct list_head tz_node; /* node in tz->thermal_instances */ 61 struct list_head tz_node; /* node in tz->thermal_instances */
@@ -853,6 +855,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
853 dev->trip = trip; 855 dev->trip = trip;
854 dev->upper = upper; 856 dev->upper = upper;
855 dev->lower = lower; 857 dev->lower = lower;
858 dev->target = THERMAL_NO_TARGET;
856 859
857 result = get_idr(&tz->idr, &tz->lock, &dev->id); 860 result = get_idr(&tz->idr, &tz->lock, &dev->id);
858 if (result) 861 if (result)
@@ -990,6 +993,7 @@ thermal_cooling_device_register(char *type, void *devdata,
990 strcpy(cdev->type, type); 993 strcpy(cdev->type, type);
991 INIT_LIST_HEAD(&cdev->thermal_instances); 994 INIT_LIST_HEAD(&cdev->thermal_instances);
992 cdev->ops = ops; 995 cdev->ops = ops;
996 cdev->updated = true;
993 cdev->device.class = &thermal_class; 997 cdev->device.class = &thermal_class;
994 cdev->devdata = devdata; 998 cdev->devdata = devdata;
995 dev_set_name(&cdev->device, "cooling_device%d", cdev->id); 999 dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
@@ -1081,6 +1085,34 @@ void thermal_cooling_device_unregister(struct
1081} 1085}
1082EXPORT_SYMBOL(thermal_cooling_device_unregister); 1086EXPORT_SYMBOL(thermal_cooling_device_unregister);
1083 1087
1088static void thermal_cdev_do_update(struct thermal_cooling_device *cdev)
1089{
1090 struct thermal_instance *instance;
1091 unsigned long target = 0;
1092
1093 /* cooling device is updated*/
1094 if (cdev->updated)
1095 return;
1096
1097 /* Make sure cdev enters the deepest cooling state */
1098 list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
1099 if (instance->target == THERMAL_NO_TARGET)
1100 continue;
1101 if (instance->target > target)
1102 target = instance->target;
1103 }
1104 cdev->ops->set_cur_state(cdev, target);
1105 cdev->updated = true;
1106}
1107
1108static void thermal_zone_do_update(struct thermal_zone_device *tz)
1109{
1110 struct thermal_instance *instance;
1111
1112 list_for_each_entry(instance, &tz->thermal_instances, tz_node)
1113 thermal_cdev_do_update(instance->cdev);
1114}
1115
1084/* 1116/*
1085 * Cooling algorithm for active trip points 1117 * Cooling algorithm for active trip points
1086 * 1118 *
@@ -1138,19 +1170,24 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz,
1138 cur_state = cur_state > instance->lower ? 1170 cur_state = cur_state > instance->lower ?
1139 (cur_state - 1) : instance->lower; 1171 (cur_state - 1) : instance->lower;
1140 } 1172 }
1141 cdev->ops->set_cur_state(cdev, cur_state); 1173 instance->target = cur_state;
1174 cdev->updated = false; /* cooling device needs update */
1142 } 1175 }
1143 } else { /* below trip */ 1176 } else { /* below trip */
1144 list_for_each_entry(instance, &tz->thermal_instances, tz_node) { 1177 list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
1145 if (instance->trip != trip) 1178 if (instance->trip != trip)
1146 continue; 1179 continue;
1147 1180
1181 /* Do not use the inactive thermal instance */
1182 if (instance->target == THERMAL_NO_TARGET)
1183 continue;
1148 cdev = instance->cdev; 1184 cdev = instance->cdev;
1149 cdev->ops->get_cur_state(cdev, &cur_state); 1185 cdev->ops->get_cur_state(cdev, &cur_state);
1150 1186
1151 cur_state = cur_state > instance->lower ? 1187 cur_state = cur_state > instance->lower ?
1152 (cur_state - 1) : instance->lower; 1188 (cur_state - 1) : THERMAL_NO_TARGET;
1153 cdev->ops->set_cur_state(cdev, cur_state); 1189 instance->target = cur_state;
1190 cdev->updated = false; /* cooling device needs update */
1154 } 1191 }
1155 } 1192 }
1156 1193
@@ -1211,6 +1248,7 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
1211 } 1248 }
1212 } 1249 }
1213 1250
1251 thermal_zone_do_update(tz);
1214 if (tz->forced_passive) 1252 if (tz->forced_passive)
1215 thermal_zone_device_passive(tz, temp, tz->forced_passive, 1253 thermal_zone_device_passive(tz, temp, tz->forced_passive,
1216 THERMAL_TRIPS_NONE); 1254 THERMAL_TRIPS_NONE);