summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/thermal/thermal_core.c31
1 files changed, 26 insertions, 5 deletions
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 89758c9934ec..a80a18cc080e 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -41,6 +41,8 @@ static struct thermal_governor *def_governor;
static bool thermal_pm_suspended;
+static struct workqueue_struct *thermal_wq __ro_after_init;
+
/*
* Governor section: set of functions to handle thermal governors
*
@@ -313,7 +315,7 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
if (delay > HZ)
delay = round_jiffies_relative(delay);
- mod_delayed_work(system_freezable_power_efficient_wq, &tz->poll_queue, delay);
+ mod_delayed_work(thermal_wq, &tz->poll_queue, delay);
}
static void thermal_zone_recheck(struct thermal_zone_device *tz, int error)
@@ -1781,6 +1783,10 @@ static void thermal_zone_device_resume(struct work_struct *work)
guard(thermal_zone)(tz);
+ /* If the thermal zone is going away, there's nothing to do. */
+ if (tz->state & TZ_STATE_FLAG_EXIT)
+ return;
+
tz->state &= ~(TZ_STATE_FLAG_SUSPENDED | TZ_STATE_FLAG_RESUMING);
thermal_debug_tz_resume(tz);
@@ -1807,6 +1813,9 @@ static void thermal_zone_pm_prepare(struct thermal_zone_device *tz)
}
tz->state |= TZ_STATE_FLAG_SUSPENDED;
+
+ /* Prevent new work from getting to the workqueue subsequently. */
+ cancel_delayed_work(&tz->poll_queue);
}
static void thermal_pm_notify_prepare(void)
@@ -1825,8 +1834,6 @@ static void thermal_zone_pm_complete(struct thermal_zone_device *tz)
{
guard(thermal_zone)(tz);
- cancel_delayed_work(&tz->poll_queue);
-
reinit_completion(&tz->resume);
tz->state |= TZ_STATE_FLAG_RESUMING;
@@ -1836,7 +1843,7 @@ static void thermal_zone_pm_complete(struct thermal_zone_device *tz)
*/
INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_resume);
/* Queue up the work without a delay. */
- mod_delayed_work(system_freezable_power_efficient_wq, &tz->poll_queue, 0);
+ mod_delayed_work(thermal_wq, &tz->poll_queue, 0);
}
static void thermal_pm_notify_complete(void)
@@ -1859,6 +1866,11 @@ static int thermal_pm_notify(struct notifier_block *nb,
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:
@@ -1891,9 +1903,16 @@ static int __init thermal_init(void)
if (result)
goto error;
+ thermal_wq = alloc_workqueue("thermal_events",
+ WQ_FREEZABLE | WQ_POWER_EFFICIENT | WQ_PERCPU, 0);
+ if (!thermal_wq) {
+ result = -ENOMEM;
+ goto unregister_netlink;
+ }
+
result = thermal_register_governors();
if (result)
- goto unregister_netlink;
+ goto destroy_workqueue;
thermal_class = kzalloc(sizeof(*thermal_class), GFP_KERNEL);
if (!thermal_class) {
@@ -1920,6 +1939,8 @@ static int __init thermal_init(void)
unregister_governors:
thermal_unregister_governors();
+destroy_workqueue:
+ destroy_workqueue(thermal_wq);
unregister_netlink:
thermal_netlink_exit();
error: