--- zzzz-none-000/linux-4.4.60/drivers/thermal/thermal_core.c 2017-04-08 07:53:53.000000000 +0000 +++ scorpion-7490-727/linux-4.4.60/drivers/thermal/thermal_core.c 2021-02-04 17:41:59.000000000 +0000 @@ -520,6 +520,56 @@ } EXPORT_SYMBOL_GPL(thermal_zone_get_temp); +void thermal_zone_set_trips(struct thermal_zone_device *tz) +{ + int low = -INT_MAX; + int high = INT_MAX; + int trip_temp, hysteresis; + int i, ret; + + mutex_lock(&tz->lock); + + if (!tz->ops->set_trips || !tz->ops->get_trip_hyst) + goto exit; + + for (i = 0; i < tz->trips; i++) { + int trip_low; + + tz->ops->get_trip_temp(tz, i, &trip_temp); + tz->ops->get_trip_hyst(tz, i, &hysteresis); + + trip_low = trip_temp - hysteresis; + + if (trip_low < tz->temperature && trip_low > low) + low = trip_low; + + if (trip_temp > tz->temperature && trip_temp < high) + high = trip_temp; + } + + /* No need to change trip points */ + if (tz->prev_low_trip == low && tz->prev_high_trip == high) + goto exit; + + tz->prev_low_trip = low; + tz->prev_high_trip = high; + + dev_dbg(&tz->device, + "new temperature boundaries: %d < x < %d\n", low, high); + + /* + * Set a temperature window. When this window is left the driver + * must inform the thermal core via thermal_zone_device_update. + */ + ret = tz->ops->set_trips(tz, low, high); + if (ret) + dev_err(&tz->device, "Failed to set trips: %d\n", ret); + +exit: + mutex_unlock(&tz->lock); +} +EXPORT_SYMBOL_GPL(thermal_zone_set_trips); + static void update_temperature(struct thermal_zone_device *tz) { int temp, ret; @@ -569,6 +619,8 @@ update_temperature(tz); + thermal_zone_set_trips(tz); + for (count = 0; count < tz->trips; count++) handle_thermal_trip(tz, count); } @@ -677,12 +729,48 @@ return sprintf(buf, "passive\n"); case THERMAL_TRIP_ACTIVE: return sprintf(buf, "active\n"); + case THERMAL_TRIP_CONFIGURABLE_HI: + return sprintf(buf, "configurable_hi\n"); + case THERMAL_TRIP_CONFIGURABLE_LOW: + return sprintf(buf, "configurable_low\n"); + case THERMAL_TRIP_CRITICAL_LOW: + return sprintf(buf, "critical_low\n"); default: return sprintf(buf, "unknown\n"); } } static ssize_t +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, ret; + char *enabled = "enabled"; + char *disabled = "disabled"; + + if (!tz->ops->set_trip_activate) + return -EPERM; + + if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip)) + return -EINVAL; + + if (!strncmp(buf, enabled, strlen(enabled))) + ret = tz->ops->set_trip_activate(tz, trip, + THERMAL_TRIP_ACTIVATION_ENABLED); + else if (!strncmp(buf, disabled, strlen(disabled))) + ret = tz->ops->set_trip_activate(tz, trip, + THERMAL_TRIP_ACTIVATION_DISABLED); + else + ret = -EINVAL; + + if (ret) + return ret; + + return count; +} + +static ssize_t trip_point_temp_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -750,6 +838,9 @@ */ ret = tz->ops->set_trip_hyst(tz, trip, temperature); + if (!ret) + thermal_zone_set_trips(tz); + return ret ? ret : count; } @@ -1257,7 +1348,7 @@ */ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, int trip, - struct thermal_cooling_device *cdev, + struct thermal_cooling_device *cdev, unsigned long upper, unsigned long lower, unsigned int weight) { @@ -1705,6 +1796,12 @@ tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO; tz->trip_type_attrs[indx].attr.show = trip_point_type_show; + if (IS_ENABLED(CONFIG_THERMAL_WRITABLE_TRIPS)) { + tz->trip_type_attrs[indx].attr.store + = trip_point_type_activate; + tz->trip_type_attrs[indx].attr.attr.mode |= S_IWUSR; + } + device_create_file(&tz->device, &tz->trip_type_attrs[indx].attr); @@ -2061,6 +2158,36 @@ } EXPORT_SYMBOL_GPL(thermal_zone_get_zone_by_name); +/** + * thermal_zone_get_slope - return the slope attribute of the thermal zone + * @tz: thermal zone device with the slope attribute + * + * Return: If the thermal zone device has a slope attribute, return it, else + * return 1. + */ +int thermal_zone_get_slope(struct thermal_zone_device *tz) +{ + if (tz && tz->tzp) + return tz->tzp->slope; + return 1; +} +EXPORT_SYMBOL_GPL(thermal_zone_get_slope); + +/** + * thermal_zone_get_offset - return the offset attribute of the thermal zone + * @tz: thermal zone device with the offset attribute + * + * Return: If the thermal zone device has a offset attribute, return it, else + * return 0. + */ +int thermal_zone_get_offset(struct thermal_zone_device *tz) +{ + if (tz && tz->tzp) + return tz->tzp->offset; + return 0; +} +EXPORT_SYMBOL_GPL(thermal_zone_get_offset); + #ifdef CONFIG_NET static const struct genl_multicast_group thermal_event_mcgrps[] = { { .name = THERMAL_GENL_MCAST_GROUP_NAME, }, @@ -2214,6 +2341,24 @@ .notifier_call = thermal_pm_notify, }; +static int thermal_panic_notify(struct notifier_block *nb, + unsigned long mode, void *_unused) +{ + struct thermal_zone_device *tz; + + list_for_each_entry(tz, &thermal_tz_list, node) { + if (tz->ops->panic_notify) + tz->ops->panic_notify(tz); + } + + return 0; +} + +static struct notifier_block panic_nb = { + .notifier_call = thermal_panic_notify, +}; + + static int __init thermal_init(void) { int result; @@ -2239,6 +2384,13 @@ pr_warn("Thermal: Can not register suspend notifier, return %d\n", result); + result = atomic_notifier_chain_register(&panic_notifier_list, + &panic_nb); + if (result) + pr_warn("Thermal: Can not register panic notifier, return %d\n", + result); + + return 0; exit_netlink: