Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

thermal: core: Suspend thermal zones later and resume them earlier

To avoid some undesirable interactions between thermal zone suspend
and resume with user space that is running when those operations are
carried out, move them closer to the suspend and resume of devices,
respectively, by updating dpm_prepare() to carry out thermal zone
suspend and dpm_complete() to start thermal zone resume (that will
continue asynchronously).

This also makes the code easier to follow by removing one, arguably
redundant, level of indirection represented by the thermal PM notifier.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
Link: https://patch.msgid.link/2036875.PYKUYFuaPT@rafael.j.wysocki

+29 -42
+5
drivers/base/power/main.c
··· 33 33 #include <trace/events/power.h> 34 34 #include <linux/cpufreq.h> 35 35 #include <linux/devfreq.h> 36 + #include <linux/thermal.h> 36 37 #include <linux/timer.h> 37 38 #include <linux/nmi.h> 38 39 ··· 1283 1282 list_splice(&list, &dpm_list); 1284 1283 mutex_unlock(&dpm_list_mtx); 1285 1284 1285 + /* Start resuming thermal control */ 1286 + thermal_pm_complete(); 1286 1287 /* Allow device probing and trigger re-probing of deferred devices */ 1287 1288 device_unblock_probing(); 1288 1289 trace_suspend_resume(TPS("dpm_complete"), state.event, false); ··· 2228 2225 * instead. The normal behavior will be restored in dpm_complete(). 2229 2226 */ 2230 2227 device_block_probing(); 2228 + /* Suspend thermal control. */ 2229 + thermal_pm_prepare(); 2231 2230 2232 2231 mutex_lock(&dpm_list_mtx); 2233 2232 while (!list_empty(&dpm_list) && !error) {
+18 -42
drivers/thermal/thermal_core.c
··· 1823 1823 cancel_delayed_work(&tz->poll_queue); 1824 1824 } 1825 1825 1826 - static void thermal_pm_notify_prepare(void) 1826 + static void __thermal_pm_prepare(void) 1827 1827 { 1828 1828 struct thermal_zone_device *tz; 1829 1829 ··· 1833 1833 1834 1834 list_for_each_entry(tz, &thermal_tz_list, node) 1835 1835 thermal_zone_pm_prepare(tz); 1836 + } 1837 + 1838 + void thermal_pm_prepare(void) 1839 + { 1840 + if (thermal_class_unavailable) 1841 + return; 1842 + 1843 + __thermal_pm_prepare(); 1844 + /* 1845 + * Allow any leftover thermal work items already on the worqueue to 1846 + * complete so they don't get in the way later. 1847 + */ 1848 + flush_workqueue(thermal_wq); 1836 1849 } 1837 1850 1838 1851 static void thermal_zone_pm_complete(struct thermal_zone_device *tz) ··· 1864 1851 mod_delayed_work(thermal_wq, &tz->poll_queue, 0); 1865 1852 } 1866 1853 1867 - static void thermal_pm_notify_complete(void) 1854 + void thermal_pm_complete(void) 1868 1855 { 1869 1856 struct thermal_zone_device *tz; 1857 + 1858 + if (thermal_class_unavailable) 1859 + return; 1870 1860 1871 1861 guard(mutex)(&thermal_list_lock); 1872 1862 ··· 1878 1862 list_for_each_entry(tz, &thermal_tz_list, node) 1879 1863 thermal_zone_pm_complete(tz); 1880 1864 } 1881 - 1882 - static int thermal_pm_notify(struct notifier_block *nb, 1883 - unsigned long mode, void *_unused) 1884 - { 1885 - switch (mode) { 1886 - case PM_HIBERNATION_PREPARE: 1887 - case PM_RESTORE_PREPARE: 1888 - case PM_SUSPEND_PREPARE: 1889 - thermal_pm_notify_prepare(); 1890 - /* 1891 - * Allow any leftover thermal work items already on the 1892 - * worqueue to complete so they don't get in the way later. 1893 - */ 1894 - flush_workqueue(thermal_wq); 1895 - break; 1896 - case PM_POST_HIBERNATION: 1897 - case PM_POST_RESTORE: 1898 - case PM_POST_SUSPEND: 1899 - thermal_pm_notify_complete(); 1900 - break; 1901 - default: 1902 - break; 1903 - } 1904 - return 0; 1905 - } 1906 - 1907 - static struct notifier_block thermal_pm_nb = { 1908 - .notifier_call = thermal_pm_notify, 1909 - /* 1910 - * Run at the lowest priority to avoid interference between the thermal 1911 - * zone resume work items spawned by thermal_pm_notify() and the other 1912 - * PM notifiers. 1913 - */ 1914 - .priority = INT_MIN, 1915 - }; 1916 1865 1917 1866 static int __init thermal_init(void) 1918 1867 { ··· 1904 1923 goto unregister_governors; 1905 1924 1906 1925 thermal_class_unavailable = false; 1907 - 1908 - result = register_pm_notifier(&thermal_pm_nb); 1909 - if (result) 1910 - pr_warn("Thermal: Can not register suspend notifier, return %d\n", 1911 - result); 1912 1926 1913 1927 return 0; 1914 1928
+6
include/linux/thermal.h
··· 273 273 int thermal_zone_device_enable(struct thermal_zone_device *tz); 274 274 int thermal_zone_device_disable(struct thermal_zone_device *tz); 275 275 void thermal_zone_device_critical(struct thermal_zone_device *tz); 276 + 277 + void thermal_pm_prepare(void); 278 + void thermal_pm_complete(void); 276 279 #else 277 280 static inline struct thermal_zone_device *thermal_zone_device_register_with_trips( 278 281 const char *type, ··· 353 350 354 351 static inline int thermal_zone_device_disable(struct thermal_zone_device *tz) 355 352 { return -ENODEV; } 353 + 354 + static inline void thermal_pm_prepare(void) {} 355 + static inline void thermal_pm_complete(void) {} 356 356 #endif /* CONFIG_THERMAL */ 357 357 358 358 #endif /* __THERMAL_H__ */