diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 1bad1ed6ed71..7b7bd1c6ac8d 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -232,30 +232,21 @@ int sensor_get_id(char *name) } EXPORT_SYMBOL(sensor_get_id); -static long get_min(struct sensor_info *sensor, long temp) +static int __update_sensor_thresholds(struct sensor_info *sensor) { - long min = LONG_MIN; - struct sensor_threshold *pos, *var; - - list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) { - if (pos->trip == THERMAL_TRIP_CONFIGURABLE_LOW) - if (pos->temp < temp && pos->temp > min) - min = pos->temp; - } - - return min; -} - -static void __update_sensor_thresholds(struct sensor_info *sensor) -{ - long min = LONG_MIN; - long max = LONG_MAX; - long max_of_min = LONG_MIN; - long min_of_max = LONG_MAX; + long max_of_low_thresh = LONG_MIN; + long min_of_high_thresh = LONG_MAX; struct sensor_threshold *pos, *var; enum thermal_trip_type type; - int i; - long curr_temp; + int i, ret = 0; + + if (!sensor->tz->ops->set_trip_temp || + !sensor->tz->ops->activate_trip_type || + !sensor->tz->ops->get_trip_type || + !sensor->tz->ops->get_trip_temp) { + ret = -ENODEV; + goto update_done; + } for (i = 0; ((sensor->max_idx == -1) || (sensor->min_idx == -1)) && (sensor->tz->ops->get_trip_type) && (i < sensor->tz->trips); @@ -271,60 +262,85 @@ static void __update_sensor_thresholds(struct sensor_info *sensor) THERMAL_TRIP_CONFIGURABLE_HI, &sensor->threshold_max); } - sensor->tz->ops->get_temp(sensor->tz, &curr_temp); list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) { + if (!pos->active) + continue; if (pos->trip == THERMAL_TRIP_CONFIGURABLE_LOW) { - if (pos->temp > max_of_min) - max_of_min = pos->temp; - if (pos->temp < curr_temp && pos->temp > min) - min = pos->temp; + if (pos->temp > max_of_low_thresh) + max_of_low_thresh = pos->temp; } if (pos->trip == THERMAL_TRIP_CONFIGURABLE_HI) { - if (pos->temp < min_of_max) - min_of_max = pos->temp; - if (pos->temp > curr_temp && pos->temp < max) - max = pos->temp; + if (pos->temp < min_of_high_thresh) + min_of_high_thresh = pos->temp; } } - pr_debug("sensor %d: min of max: %ld max of min: %ld\n", - sensor->sensor_id, max_of_min, min_of_max); + pr_debug("sensor %d: Thresholds: max of low: %ld min of high: %ld\n", + sensor->sensor_id, max_of_low_thresh, + min_of_high_thresh); - /* If we haven't found a max and min bounding the curr_temp, - * use the min of max and max of min instead. - */ - if (max == LONG_MAX) - max = min_of_max; - if (min == LONG_MIN) { - min = get_min(sensor, max); - if (min == LONG_MIN) - min = max_of_min; + if ((min_of_high_thresh != sensor->threshold_max) && + (min_of_high_thresh != LONG_MAX)) { + ret = sensor->tz->ops->set_trip_temp(sensor->tz, + sensor->max_idx, min_of_high_thresh); + if (ret) { + pr_err("sensor %d: Unable to set high threshold %d", + sensor->sensor_id, ret); + goto update_done; + } + sensor->threshold_max = min_of_high_thresh; + } + ret = sensor->tz->ops->activate_trip_type(sensor->tz, + sensor->max_idx, + (min_of_high_thresh == LONG_MAX) ? + THERMAL_TRIP_ACTIVATION_DISABLED : + THERMAL_TRIP_ACTIVATION_ENABLED); + if (ret) { + pr_err("sensor %d: Unable to activate high threshold %d", + sensor->sensor_id, ret); + goto update_done; } - if (sensor->tz->ops->set_trip_temp) { - if (max != sensor->threshold_max) { - sensor->tz->ops->set_trip_temp(sensor->tz, - sensor->max_idx, max); - sensor->threshold_max = max; - } - if (min != sensor->threshold_min) { - sensor->tz->ops->set_trip_temp(sensor->tz, - sensor->min_idx, min); - sensor->threshold_min = min; + if ((max_of_low_thresh != sensor->threshold_min) && + (max_of_low_thresh != LONG_MIN)) { + ret = sensor->tz->ops->set_trip_temp(sensor->tz, + sensor->min_idx, max_of_low_thresh); + if (ret) { + pr_err("sensor %d: Unable to set low threshold %d", + sensor->sensor_id, ret); + goto update_done; } + sensor->threshold_min = max_of_low_thresh; + } + ret = sensor->tz->ops->activate_trip_type(sensor->tz, + sensor->min_idx, + (max_of_low_thresh == LONG_MIN) ? + THERMAL_TRIP_ACTIVATION_DISABLED : + THERMAL_TRIP_ACTIVATION_ENABLED); + if (ret) { + pr_err("sensor %d: Unable to activate low threshold %d", + sensor->sensor_id, ret); + goto update_done; } - pr_debug("sensor %d: curr_temp: %ld min: %ld max: %ld\n", - sensor->sensor_id, curr_temp, + pr_debug("sensor %d: low: %ld high: %ld\n", + sensor->sensor_id, sensor->threshold_min, sensor->threshold_max); + +update_done: + return ret; } static void sensor_update_work(struct work_struct *work) { struct sensor_info *sensor = container_of(work, struct sensor_info, work); + int ret = 0; mutex_lock(&sensor->lock); - __update_sensor_thresholds(sensor); + ret = __update_sensor_thresholds(sensor); + if (ret) + pr_err("sensor %d: Error %d setting threshold\n", + sensor->sensor_id, ret); mutex_unlock(&sensor->lock); } @@ -345,7 +361,7 @@ int thermal_sensor_trip(struct thermal_zone_device *tz, return 0; list_for_each_entry_safe(pos, var, &tz->sensor.threshold_list, list) { - if (pos->trip != trip) + if ((pos->trip != trip) || (!pos->active)) continue; if (((trip == THERMAL_TRIP_CONFIGURABLE_LOW) && (pos->temp <= tz->sensor.threshold_min) && @@ -353,6 +369,7 @@ int thermal_sensor_trip(struct thermal_zone_device *tz, ((trip == THERMAL_TRIP_CONFIGURABLE_HI) && (pos->temp >= tz->sensor.threshold_max) && (pos->temp <= temp))) { + pos->active = 0; pos->notify(trip, temp, pos->data); } } @@ -363,6 +380,29 @@ int thermal_sensor_trip(struct thermal_zone_device *tz, } EXPORT_SYMBOL(thermal_sensor_trip); +int sensor_activate_trip(uint32_t sensor_id, + struct sensor_threshold *threshold, bool enable) +{ + struct sensor_info *sensor = get_sensor(sensor_id); + int ret = 0; + + if (!sensor || !threshold) { + pr_err("%s: uninitialized data\n", + KBUILD_MODNAME); + ret = -ENODEV; + goto activate_trip_exit; + } + + mutex_lock(&sensor->lock); + threshold->active = (enable) ? 1 : 0; + ret = __update_sensor_thresholds(sensor); + mutex_unlock(&sensor->lock); + +activate_trip_exit: + return ret; +} +EXPORT_SYMBOL(sensor_activate_trip); + int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold) { struct sensor_threshold *pos, *var; @@ -384,8 +424,8 @@ int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold) INIT_LIST_HEAD(&threshold->list); list_add(&threshold->list, &sensor->threshold_list); } + threshold->active = 0; /* Do not allow active threshold right away */ - __update_sensor_thresholds(sensor); mutex_unlock(&sensor->lock); return 0; @@ -397,6 +437,7 @@ int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold) { struct sensor_threshold *pos, *var; struct sensor_info *sensor = get_sensor(sensor_id); + int ret = 0; if (!sensor) return -ENODEV; @@ -404,15 +445,16 @@ int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold) mutex_lock(&sensor->lock); list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) { if (pos == threshold) { + pos->active = 0; list_del(&pos->list); break; } } - __update_sensor_thresholds(sensor); + ret = __update_sensor_thresholds(sensor); mutex_unlock(&sensor->lock); - return 0; + return ret; } EXPORT_SYMBOL(sensor_cancel_trip); @@ -426,36 +468,36 @@ static int tz_notify_trip(enum thermal_trip_type type, int temp, void *data) return 0; } +static void get_trip_threshold(struct thermal_zone_device *tz, int trip, + struct sensor_threshold **threshold) +{ + enum thermal_trip_type type; + + tz->ops->get_trip_type(tz, trip, &type); + + if (type == THERMAL_TRIP_CONFIGURABLE_HI) + *threshold = &tz->tz_threshold[0]; + else if (type == THERMAL_TRIP_CONFIGURABLE_LOW) + *threshold = &tz->tz_threshold[1]; + else + *threshold = NULL; +} + int sensor_set_trip_temp(struct thermal_zone_device *tz, int trip, long temp) { int ret = 0; - enum thermal_trip_type type; + struct sensor_threshold *threshold = NULL; if (!tz->ops->get_trip_type) return -EPERM; - tz->ops->get_trip_type(tz, trip, &type); - switch (type) { - case THERMAL_TRIP_CONFIGURABLE_HI: - tz->tz_threshold[0].temp = temp; - tz->tz_threshold[0].trip = THERMAL_TRIP_CONFIGURABLE_HI; - tz->tz_threshold[0].notify = tz_notify_trip; - tz->tz_threshold[0].data = tz; - ret = sensor_set_trip(tz->sensor.sensor_id, - &tz->tz_threshold[0]); - break; - case THERMAL_TRIP_CONFIGURABLE_LOW: - tz->tz_threshold[1].temp = temp; - tz->tz_threshold[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW; - tz->tz_threshold[1].notify = tz_notify_trip; - tz->tz_threshold[1].data = tz; - ret = sensor_set_trip(tz->sensor.sensor_id, - &tz->tz_threshold[1]); - break; - default: + get_trip_threshold(tz, trip, &threshold); + if (threshold) { + threshold->temp = temp; + ret = sensor_set_trip(tz->sensor.sensor_id, threshold); + } else { ret = tz->ops->set_trip_temp(tz, trip, temp); - break; } return ret; @@ -476,10 +518,12 @@ int sensor_init(struct thermal_zone_device *tz) INIT_LIST_HEAD(&sensor->threshold_list); INIT_LIST_HEAD(&tz->tz_threshold[0].list); INIT_LIST_HEAD(&tz->tz_threshold[1].list); - tz->tz_threshold[0].notify = NULL; - tz->tz_threshold[0].data = NULL; - tz->tz_threshold[1].notify = NULL; - tz->tz_threshold[1].data = NULL; + tz->tz_threshold[0].notify = tz_notify_trip; + tz->tz_threshold[0].data = tz; + tz->tz_threshold[0].trip = THERMAL_TRIP_CONFIGURABLE_HI; + tz->tz_threshold[1].notify = tz_notify_trip; + tz->tz_threshold[1].data = tz; + tz->tz_threshold[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW; list_add(&sensor->sensor_list, &sensor_info_list); INIT_WORK(&sensor->work, sensor_update_work); @@ -961,23 +1005,40 @@ trip_point_type_activate(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct thermal_zone_device *tz = to_thermal_zone(dev); - int trip, result; + int trip, result = 0; + bool activate; + struct sensor_threshold *threshold = NULL; - if (!tz->ops->activate_trip_type) - return -EPERM; + if (!tz->ops->get_trip_type || + !tz->ops->activate_trip_type) { + result = -EPERM; + goto trip_activate_exit; + } - if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip)) - return -EINVAL; - - if (!strncmp(buf, "enabled", sizeof("enabled"))) - result = tz->ops->activate_trip_type(tz, trip, - THERMAL_TRIP_ACTIVATION_ENABLED); - else if (!strncmp(buf, "disabled", sizeof("disabled"))) - result = tz->ops->activate_trip_type(tz, trip, - THERMAL_TRIP_ACTIVATION_DISABLED); - else + if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip)) { result = -EINVAL; + goto trip_activate_exit; + } + if (!strcmp(buf, "enabled")) { + activate = true; + } else if (!strcmp(buf, "disabled")) { + activate = false; + } else { + result = -EINVAL; + goto trip_activate_exit; + } + + get_trip_threshold(tz, trip, &threshold); + if (threshold) + result = sensor_activate_trip(tz->sensor.sensor_id, + threshold, activate); + else + result = tz->ops->activate_trip_type(tz, trip, + activate ? THERMAL_TRIP_ACTIVATION_ENABLED : + THERMAL_TRIP_ACTIVATION_DISABLED); + +trip_activate_exit: if (result) return result; diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 2bab7a26db20..89de2ca82974 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -158,6 +158,7 @@ struct sensor_threshold { enum thermal_trip_type trip; int (*notify)(enum thermal_trip_type type, int temp, void *data); void *data; + uint8_t active; struct list_head list; }; @@ -449,6 +450,8 @@ void thermal_notify_framework(struct thermal_zone_device *, int); int sensor_get_id(char *name); int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold); int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold); +int sensor_activate_trip(uint32_t sensor_id, struct sensor_threshold *threshold, + bool enable); int thermal_sensor_trip(struct thermal_zone_device *tz, enum thermal_trip_type trip, long temp);