summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/base/power/main.c5
-rw-r--r--drivers/thermal/thermal_core.c60
-rw-r--r--include/linux/thermal.h6
3 files changed, 29 insertions, 42 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 189de5250f25..e1b550664bab 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -33,6 +33,7 @@
#include <trace/events/power.h>
#include <linux/cpufreq.h>
#include <linux/devfreq.h>
+#include <linux/thermal.h>
#include <linux/timer.h>
#include <linux/nmi.h>
@@ -1282,6 +1283,8 @@ void dpm_complete(pm_message_t state)
list_splice(&list, &dpm_list);
mutex_unlock(&dpm_list_mtx);
+ /* Start resuming thermal control */
+ thermal_pm_complete();
/* Allow device probing and trigger re-probing of deferred devices */
device_unblock_probing();
trace_suspend_resume(TPS("dpm_complete"), state.event, false);
@@ -2225,6 +2228,8 @@ int dpm_prepare(pm_message_t state)
* instead. The normal behavior will be restored in dpm_complete().
*/
device_block_probing();
+ /* Suspend thermal control. */
+ thermal_pm_prepare();
mutex_lock(&dpm_list_mtx);
while (!list_empty(&dpm_list) && !error) {
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index f0f3a628c00c..2f4e2dc46b8f 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -1823,7 +1823,7 @@ static void thermal_zone_pm_prepare(struct thermal_zone_device *tz)
cancel_delayed_work(&tz->poll_queue);
}
-static void thermal_pm_notify_prepare(void)
+static void __thermal_pm_prepare(void)
{
struct thermal_zone_device *tz;
@@ -1835,6 +1835,19 @@ static void thermal_pm_notify_prepare(void)
thermal_zone_pm_prepare(tz);
}
+void thermal_pm_prepare(void)
+{
+ if (thermal_class_unavailable)
+ return;
+
+ __thermal_pm_prepare();
+ /*
+ * Allow any leftover thermal work items already on the worqueue to
+ * complete so they don't get in the way later.
+ */
+ flush_workqueue(thermal_wq);
+}
+
static void thermal_zone_pm_complete(struct thermal_zone_device *tz)
{
guard(thermal_zone)(tz);
@@ -1851,10 +1864,13 @@ static void thermal_zone_pm_complete(struct thermal_zone_device *tz)
mod_delayed_work(thermal_wq, &tz->poll_queue, 0);
}
-static void thermal_pm_notify_complete(void)
+void thermal_pm_complete(void)
{
struct thermal_zone_device *tz;
+ if (thermal_class_unavailable)
+ return;
+
guard(mutex)(&thermal_list_lock);
thermal_pm_suspended = false;
@@ -1863,41 +1879,6 @@ static void thermal_pm_notify_complete(void)
thermal_zone_pm_complete(tz);
}
-static int thermal_pm_notify(struct notifier_block *nb,
- unsigned long mode, void *_unused)
-{
- switch (mode) {
- case PM_HIBERNATION_PREPARE:
- case PM_RESTORE_PREPARE:
- case PM_SUSPEND_PREPARE:
- thermal_pm_notify_prepare();
- /*
- * Allow any leftover thermal work items already on the
- * worqueue to complete so they don't get in the way later.
- */
- flush_workqueue(thermal_wq);
- break;
- case PM_POST_HIBERNATION:
- case PM_POST_RESTORE:
- case PM_POST_SUSPEND:
- thermal_pm_notify_complete();
- break;
- default:
- break;
- }
- return 0;
-}
-
-static struct notifier_block thermal_pm_nb = {
- .notifier_call = thermal_pm_notify,
- /*
- * Run at the lowest priority to avoid interference between the thermal
- * zone resume work items spawned by thermal_pm_notify() and the other
- * PM notifiers.
- */
- .priority = INT_MIN,
-};
-
static int __init thermal_init(void)
{
int result;
@@ -1924,11 +1905,6 @@ static int __init thermal_init(void)
thermal_class_unavailable = false;
- result = register_pm_notifier(&thermal_pm_nb);
- if (result)
- pr_warn("Thermal: Can not register suspend notifier, return %d\n",
- result);
-
return 0;
unregister_governors:
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 0b5ed6821080..0ddc77aeeca2 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -273,6 +273,9 @@ bool thermal_trip_is_bound_to_cdev(struct thermal_zone_device *tz,
int thermal_zone_device_enable(struct thermal_zone_device *tz);
int thermal_zone_device_disable(struct thermal_zone_device *tz);
void thermal_zone_device_critical(struct thermal_zone_device *tz);
+
+void thermal_pm_prepare(void);
+void thermal_pm_complete(void);
#else
static inline struct thermal_zone_device *thermal_zone_device_register_with_trips(
const char *type,
@@ -350,6 +353,9 @@ static inline int thermal_zone_device_enable(struct thermal_zone_device *tz)
static inline int thermal_zone_device_disable(struct thermal_zone_device *tz)
{ return -ENODEV; }
+
+static inline void thermal_pm_prepare(void) {}
+static inline void thermal_pm_complete(void) {}
#endif /* CONFIG_THERMAL */
#endif /* __THERMAL_H__ */