--- zzzz-none-000/linux-4.4.271/drivers/thermal/thermal_core.c 2021-06-03 06:22:09.000000000 +0000 +++ dakota-7530ac-750/linux-4.4.271/drivers/thermal/thermal_core.c 2023-01-11 09:25:42.000000000 +0000 @@ -38,6 +38,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -426,6 +427,16 @@ def_governor->throttle(tz, trip); } +static int thermal_reboot_print_thermal_zone(struct thermal_zone_device *tz, void *data) +{ + int temp; + + if (!thermal_zone_get_temp(tz, &temp)) + pr_emerg("%s(%s): %d °C\n", dev_name(&tz->device), tz->type, temp); + + return 0; +} + static void handle_critical_trips(struct thermal_zone_device *tz, int trip, enum thermal_trip_type trip_type) { @@ -442,11 +453,17 @@ if (tz->ops->notify) tz->ops->notify(tz, trip, trip_type); - if (trip_type == THERMAL_TRIP_CRITICAL) { + if (trip_type == THERMAL_TRIP_AVM_HOT) { dev_emerg(&tz->device, - "critical temperature reached(%d C),shutting down\n", - tz->temperature / 1000); - orderly_poweroff(true); + "critical temperature reached (%d C)\n", + tz->temperature); + } else if (trip_type == THERMAL_TRIP_CRITICAL) { + dev_emerg(&tz->device, + "critical temperature reached (%d C), shutting down\n", + tz->temperature); + avm_set_reset_status(RS_TEMP_REBOOT); + panic("OVERHEAT! Thermal shutdown to prevent damage: crash (%s: %d °C)\n", dev_name(&tz->device), + tz->temperature); } } @@ -460,7 +477,7 @@ tz->ops->get_trip_type(tz, trip, &type); - if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT) + if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT || type == THERMAL_TRIP_AVM_HOT) handle_critical_trips(tz, trip, type); else handle_non_critical_trips(tz, trip, type); @@ -520,6 +537,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 +636,8 @@ update_temperature(tz); + thermal_zone_set_trips(tz); + for (count = 0; count < tz->trips; count++) handle_thermal_trip(tz, count); } @@ -582,6 +651,57 @@ thermal_zone_device_update(tz); } +int for_each_thermal_governor(int (*cb)(struct thermal_governor *, void *), + void *data) +{ + struct thermal_governor *gov; + int ret = 0; + + mutex_lock(&thermal_governor_lock); + list_for_each_entry(gov, &thermal_governor_list, governor_list) { + ret = cb(gov, data); + if (ret) + break; + } + mutex_unlock(&thermal_governor_lock); + + return ret; +} + +int for_each_thermal_cooling_device(int (*cb)(struct thermal_cooling_device *, + void *), void *data) +{ + struct thermal_cooling_device *cdev; + int ret = 0; + + mutex_lock(&thermal_list_lock); + list_for_each_entry(cdev, &thermal_cdev_list, node) { + ret = cb(cdev, data); + if (ret) + break; + } + mutex_unlock(&thermal_list_lock); + + return ret; +} + +int for_each_thermal_zone(int (*cb)(struct thermal_zone_device *, void *), + void *data) +{ + struct thermal_zone_device *tz; + int ret = 0; + + mutex_lock(&thermal_list_lock); + list_for_each_entry(tz, &thermal_tz_list, node) { + ret = cb(tz, data); + if (ret) + break; + } + mutex_unlock(&thermal_list_lock); + + return ret; +} + /* sys I/F for thermal zone */ #define to_thermal_zone(_dev) \ @@ -677,12 +797,50 @@ 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"); + case THERMAL_TRIP_AVM_HOT: + return sprintf(buf, "avm_hot\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 +908,9 @@ */ ret = tz->ops->set_trip_hyst(tz, trip, temperature); + if (!ret) + thermal_zone_set_trips(tz); + return ret ? ret : count; } @@ -1257,7 +1418,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 +1866,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 +2228,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 +2411,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); + } + for_each_thermal_zone(thermal_reboot_print_thermal_zone, NULL); + return 0; +} + +static struct notifier_block panic_nb = { + .notifier_call = thermal_panic_notify, +}; + + static int __init thermal_init(void) { int result; @@ -2239,6 +2454,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: