--- zzzz-none-000/linux-5.4.213/drivers/thermal/thermal_core.c 2022-09-15 10:04:56.000000000 +0000 +++ alder-5690pro-762/linux-5.4.213/drivers/thermal/thermal_core.c 2024-08-14 09:02:08.000000000 +0000 @@ -22,6 +22,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -45,7 +46,7 @@ static DEFINE_MUTEX(poweroff_lock); static atomic_t in_suspend; -static bool power_off_triggered; +static bool power_off_triggered __maybe_unused; static struct thermal_governor *def_governor; @@ -326,6 +327,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, DIV_ROUND_CLOSEST(temp, 1000)); + + return 0; +} + /** * thermal_emergency_poweroff_func - emergency poweroff work after a known delay * @work: work_struct associated with the emergency poweroff function @@ -333,7 +344,7 @@ * This function is called in very critical situations to force * a kernel poweroff after a configurable timeout value. */ -static void thermal_emergency_poweroff_func(struct work_struct *work) +static void __maybe_unused thermal_emergency_poweroff_func(struct work_struct *work) { /* * We have reached here after the emergency thermal shutdown @@ -361,7 +372,7 @@ * This may be called from any critical situation to trigger a system shutdown * after a known period of time. By default this is not scheduled. */ -static void thermal_emergency_poweroff(void) +static void __maybe_unused thermal_emergency_poweroff(void) { int poweroff_delay_ms = CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS; /* @@ -390,10 +401,23 @@ 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)\n", + DIV_ROUND_CLOSEST(tz->temperature, 1000)); + } else if (trip_type == THERMAL_TRIP_CRITICAL) { + /* + * normally this should be millicelsius (so divide by 1000), + * but QCA does not reflect this in there device trees + */ dev_emerg(&tz->device, "critical temperature reached (%d C), shutting down\n", - tz->temperature / 1000); + DIV_ROUND_CLOSEST(tz->temperature, 1000)); +#ifdef CONFIG_AVM_ENHANCED + avm_set_reset_status(RS_TEMP_REBOOT); + panic("OVERHEAT! Thermal shutdown to prevent damage: crash (%s: %d °C)\n", dev_name(&tz->device), + DIV_ROUND_CLOSEST(tz->temperature, 1000)); +#else mutex_lock(&poweroff_lock); if (!power_off_triggered) { /* @@ -405,6 +429,7 @@ power_off_triggered = true; } mutex_unlock(&poweroff_lock); +#endif } } @@ -418,7 +443,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); @@ -512,6 +537,57 @@ } EXPORT_SYMBOL_GPL(thermal_notify_framework); +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; +} + static void thermal_zone_device_check(struct work_struct *work) { struct thermal_zone_device *tz = container_of(work, struct @@ -1595,6 +1671,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; @@ -1621,6 +1715,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: