aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/thermal/thermal_sys.c44
-rw-r--r--include/linux/thermal.h1
2 files changed, 42 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);
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 9ae378a4a555..de0515a96f9f 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -94,6 +94,7 @@ struct thermal_cooling_device {
94 struct device device; 94 struct device device;
95 void *devdata; 95 void *devdata;
96 const struct thermal_cooling_device_ops *ops; 96 const struct thermal_cooling_device_ops *ops;
97 bool updated; /* true if the cooling device does not need update */
97 struct list_head thermal_instances; 98 struct list_head thermal_instances;
98 struct list_head node; 99 struct list_head node;
99}; 100};