diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index c6f6f0337d1..4d194e339ac 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -37,6 +37,7 @@ #include #define MAX_RAILS 5 +#define MAX_THRESHOLD 2 static struct msm_thermal_data msm_thermal_info; static uint32_t limited_max_freq = UINT_MAX; @@ -77,8 +78,10 @@ struct cpu_info { uint32_t cpu; bool offline; bool user_offline; + bool thresh_cleared; const char *sensor_type; - struct sensor_threshold thresh[2]; + uint32_t sensor_id; + struct sensor_threshold thresh[MAX_THRESHOLD]; }; struct rail { @@ -624,6 +627,76 @@ static int update_cpu_max_freq(int cpu, uint32_t max_freq) return ret; } +static int set_and_activate_threshold(uint32_t sensor_id, + struct sensor_threshold *threshold) +{ + int ret = 0; + + ret = sensor_set_trip(sensor_id, threshold); + if (ret != 0) { + pr_err("%s: Error in setting trip %d\n", + KBUILD_MODNAME, threshold->trip); + goto set_done; + } + + ret = sensor_activate_trip(sensor_id, threshold, true); + if (ret != 0) { + pr_err("%s: Error in enabling trip %d\n", + KBUILD_MODNAME, threshold->trip); + goto set_done; + } + +set_done: + return ret; +} + +static int set_threshold(uint32_t sensor_id, + struct sensor_threshold *threshold) +{ + struct tsens_device tsens_dev; + int i = 0, ret = 0; + long temp; + + if ((!threshold) || check_sensor_id(sensor_id)) { + pr_err("%s: Invalid input\n", KBUILD_MODNAME); + ret = -EINVAL; + goto set_threshold_exit; + } + + tsens_dev.sensor_num = sensor_id; + ret = tsens_get_temp(&tsens_dev, &temp); + if (ret) { + pr_err("%s: Unable to read TSENS sensor %d\n", + KBUILD_MODNAME, tsens_dev.sensor_num); + goto set_threshold_exit; + } + while (i < MAX_THRESHOLD) { + switch (threshold[i].trip) { + case THERMAL_TRIP_CONFIGURABLE_HI: + if (threshold[i].temp >= temp) { + ret = set_and_activate_threshold(sensor_id, + &threshold[i]); + if (ret) + goto set_threshold_exit; + } + break; + case THERMAL_TRIP_CONFIGURABLE_LOW: + if (threshold[i].temp <= temp) { + ret = set_and_activate_threshold(sensor_id, + &threshold[i]); + if (ret) + goto set_threshold_exit; + } + break; + default: + break; + } + i++; + } +set_threshold_exit: + return ret; +} + #ifdef CONFIG_SMP static void __ref do_core_control(long temp) { @@ -677,7 +750,7 @@ static void __ref do_core_control(long temp) /* Call with core_control_mutex locked */ static int __ref update_offline_cores(int val) { - int cpu = 0; + uint32_t cpu = 0; int ret = 0; if (!core_control_enabled) @@ -701,8 +774,7 @@ static int __ref update_offline_cores(int val) static __ref int do_hotplug(void *data) { int ret = 0; - int cpu = 0; - uint32_t mask = 0; + uint32_t cpu = 0, mask = 0; if (!core_control_enabled) return -EINVAL; @@ -714,6 +786,11 @@ static __ref int do_hotplug(void *data) mutex_lock(&core_control_mutex); for_each_possible_cpu(cpu) { + if (cpus[cpu].thresh_cleared) { + set_threshold(cpus[cpu].sensor_id, + cpus[cpu].thresh); + cpus[cpu].thresh_cleared = false; + } if (cpus[cpu].offline || cpus[cpu].user_offline) mask |= BIT(cpu); } @@ -984,10 +1061,12 @@ static int hotplug_notify(enum thermal_trip_type type, int temp, void *data) default: break; } - if (hotplug_task) + if (hotplug_task) { + cpu_node->thresh_cleared = true; complete(&hotplug_notify_complete); - else + } else { pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME); + } return 0; } /* Adjust cpus offlined bit based on temperature reading. */ @@ -1001,8 +1080,7 @@ static int hotplug_init_cpu_offlined(void) for_each_possible_cpu(cpu) { if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu))) continue; - tsens_dev.sensor_num = sensor_get_id(\ - (char *)cpus[cpu].sensor_type); + tsens_dev.sensor_num = cpus[cpu].sensor_id; if (tsens_get_temp(&tsens_dev, &temp)) { pr_err("%s: Unable to read TSENS sensor %d\n", KBUILD_MODNAME, tsens_dev.sensor_num); @@ -1035,24 +1113,23 @@ static void hotplug_init(void) return; for_each_possible_cpu(cpu) { + cpus[cpu].cpu = (uint32_t)cpu; + cpus[cpu].thresh_cleared = false; + cpus[cpu].sensor_id = + sensor_get_id((char *)cpus[cpu].sensor_type); if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu))) continue; - cpus[cpu].cpu = (uint32_t)cpu; cpus[cpu].thresh[0].temp = msm_thermal_info.hotplug_temp_degC; cpus[cpu].thresh[0].trip = THERMAL_TRIP_CONFIGURABLE_HI; cpus[cpu].thresh[0].notify = hotplug_notify; cpus[cpu].thresh[0].data = (void *)&cpus[cpu]; - sensor_set_trip(sensor_get_id((char *)cpus[cpu].sensor_type), - &cpus[cpu].thresh[0]); cpus[cpu].thresh[1].temp = msm_thermal_info.hotplug_temp_degC - msm_thermal_info.hotplug_temp_hysteresis_degC; cpus[cpu].thresh[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW; cpus[cpu].thresh[1].notify = hotplug_notify; cpus[cpu].thresh[1].data = (void *)&cpus[cpu]; - sensor_set_trip(sensor_get_id((char *)cpus[cpu].sensor_type), - &cpus[cpu].thresh[1]); - + set_threshold(cpus[cpu].sensor_id, cpus[cpu].thresh); } init_completion(&hotplug_notify_complete); hotplug_task = kthread_run(do_hotplug, NULL, "msm_thermal:hotplug"); diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 8d9da6b37ac..739696dbc04 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -89,30 +89,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); @@ -128,60 +119,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); } @@ -202,7 +218,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) && @@ -210,6 +226,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); } } @@ -220,6 +237,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("Sensor %d: uninitialized data\n", + sensor_id); + 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; @@ -241,8 +281,7 @@ int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold) INIT_LIST_HEAD(&threshold->list); list_add(&threshold->list, &sensor->threshold_list); } - - __update_sensor_thresholds(sensor); + threshold->active = 0; /* Do not allow active threshold right away */ mutex_unlock(&sensor->lock); return 0; @@ -254,6 +293,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; @@ -261,15 +301,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); @@ -283,36 +324,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; @@ -333,10 +374,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); @@ -489,23 +532,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 ed6d41b7e80..faf98fe5704 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -102,6 +102,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; }; @@ -189,6 +190,8 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *); 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);