Merge branches 'pm-sleep', 'pm-powercap' and 'pm-tools'

Merge updates related to system sleep support, two updates of the
intel_rapl power capping driver, and a pm-graph utility fix for
7.2-rc1:

 - Add sysctl interface for DPM watchdog timeouts (Tzung-Bi Shih)

 - Use complete() instead of complete_all() in device_pm_sleep_init() to
   avoid a false-positive warning from lockdep_assert_RT_in_threaded_ctx()
   when CONFIG_PROVE_RAW_LOCK_NESTING is enabled (Jiakai Xu)

 - Use a flexible array for CRC uncompressed buffers during hibernation
   image saving (Rosen Penev)

 - Make the LZ4 algorithm available for hibernation compression (l1rox3)

 - Move the preallocate_image() call during hibernation after the
   "prepare" phase of the "freeze" transition (Matthew Leach)

 - Fix a memory leak in rapl_add_package_cpuslocked() in the intel_rapl
   power capping driver and use sysfs_emit() in cpumask_show() in that
   driver (Sumeet Pawnikar, Yury Norov)

 - Fix ValueError when parsing incomplete device properties in the
   pm-graph utility (Gongwei Li)

* pm-sleep:
  PM: dpm_watchdog: Add sysctl interface for DPM watchdog timeouts
  PM: hibernate: Use flexible array for CRC uncompressed buffers
  PM: hibernate: make LZ4 available for hibernation compression
  PM: sleep: Use complete() in device_pm_sleep_init()
  PM: hibernate: call preallocate_image() after freeze prepare

* pm-powercap:
  powercap: intel_rapl: Use sysfs_emit() in cpumask_show()
  powercap: intel_rapl: Fix memory leak in rapl_add_package_cpuslocked()

* pm-tools:
  PM: tools: pm-graph: fix ValueError when parsing incomplete device properties
This commit is contained in:
Rafael J. Wysocki 2026-06-11 21:42:36 +02:00
commit 5ca48f6f2a
6 changed files with 79 additions and 55 deletions

View File

@ -28,6 +28,7 @@
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/sched/debug.h>
#include <linux/sysctl.h>
#include <linux/async.h>
#include <linux/suspend.h>
#include <trace/events/power.h>
@ -115,7 +116,7 @@ void device_pm_sleep_init(struct device *dev)
dev->power.is_noirq_suspended = false;
dev->power.is_late_suspended = false;
init_completion(&dev->power.completion);
complete_all(&dev->power.completion);
complete(&dev->power.completion);
dev->power.wakeup = NULL;
INIT_LIST_HEAD(&dev->power.entry);
}
@ -252,6 +253,10 @@ static void dpm_wait(struct device *dev, bool async)
if (!dev)
return;
/* Devices with no PM support don't use the completion. */
if (dev->power.no_pm)
return;
if (async || (pm_async_enabled && dev->power.async_suspend))
wait_for_completion(&dev->power.completion);
}
@ -527,6 +532,58 @@ module_param(dpm_watchdog_all_cpu_backtrace, bool, 0644);
MODULE_PARM_DESC(dpm_watchdog_all_cpu_backtrace,
"Backtrace all CPUs on DPM watchdog timeout");
static unsigned int __read_mostly dpm_watchdog_timeout = CONFIG_DPM_WATCHDOG_TIMEOUT;
static unsigned int __read_mostly dpm_watchdog_warning_timeout =
CONFIG_DPM_WATCHDOG_WARNING_TIMEOUT;
static const unsigned int dpm_watchdog_timeout_max = CONFIG_DPM_WATCHDOG_TIMEOUT;
static int proc_dodpm_watchdog_timeout_secs(const struct ctl_table *table,
int write, void *buffer,
size_t *lenp, loff_t *ppos)
{
struct ctl_table ctl = *table;
unsigned int val = dpm_watchdog_timeout;
int ret;
ctl.data = &val;
ret = proc_douintvec_minmax(&ctl, write, buffer, lenp, ppos);
if (ret || !write)
return ret;
if (val < dpm_watchdog_warning_timeout)
dpm_watchdog_warning_timeout = val;
dpm_watchdog_timeout = val;
return 0;
}
static const struct ctl_table dpm_watchdog_sysctls[] = {
{
.procname = "dpm_watchdog_timeout_secs",
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = proc_dodpm_watchdog_timeout_secs,
.extra1 = SYSCTL_ONE,
.extra2 = (void *)&dpm_watchdog_timeout_max,
},
{
.procname = "dpm_watchdog_warning_timeout_secs",
.data = &dpm_watchdog_warning_timeout,
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = proc_douintvec_minmax,
.extra1 = SYSCTL_ONE,
.extra2 = (void *)&dpm_watchdog_timeout,
},
};
static int __init dpm_watchdog_sysctl_init(void)
{
register_sysctl_init("kernel", dpm_watchdog_sysctls);
return 0;
}
subsys_initcall(dpm_watchdog_sysctl_init);
/**
* dpm_watchdog_handler - Driver suspend / resume watchdog handler.
* @t: The timer that PM watchdog depends on.
@ -552,9 +609,9 @@ static void dpm_watchdog_handler(struct timer_list *t)
dev_driver_string(wd->dev), dev_name(wd->dev));
}
time_left = CONFIG_DPM_WATCHDOG_TIMEOUT - CONFIG_DPM_WATCHDOG_WARNING_TIMEOUT;
time_left = dpm_watchdog_timeout - dpm_watchdog_warning_timeout;
dev_warn(wd->dev, "**** DPM device timeout after %u seconds; %u seconds until panic ****\n",
CONFIG_DPM_WATCHDOG_WARNING_TIMEOUT, time_left);
dpm_watchdog_warning_timeout, time_left);
show_stack(wd->tsk, NULL, KERN_WARNING);
wd->fatal = true;
@ -572,11 +629,11 @@ static void dpm_watchdog_set(struct dpm_watchdog *wd, struct device *dev)
wd->dev = dev;
wd->tsk = current;
wd->fatal = CONFIG_DPM_WATCHDOG_TIMEOUT == CONFIG_DPM_WATCHDOG_WARNING_TIMEOUT;
wd->fatal = dpm_watchdog_timeout == dpm_watchdog_warning_timeout;
timer_setup_on_stack(timer, dpm_watchdog_handler, 0);
/* use same timeout value for both suspend and resume */
timer->expires = jiffies + HZ * CONFIG_DPM_WATCHDOG_WARNING_TIMEOUT;
timer->expires = jiffies + HZ * dpm_watchdog_warning_timeout;
add_timer(timer);
}

View File

@ -1441,7 +1441,7 @@ static ssize_t cpumask_show(struct device *dev,
}
cpus_read_unlock();
ret = cpumap_print_to_pagebuf(true, buf, cpu_mask);
ret = sysfs_emit(buf, "%*pbl\n", cpumask_pr_args(cpu_mask));
free_cpumask_var(cpu_mask);
@ -1770,7 +1770,8 @@ struct rapl_package *rapl_add_package_cpuslocked(int id, struct rapl_if_priv *pr
topology_physical_package_id(id) : topology_logical_die_id(id);
if ((int)(rp->id) < 0) {
pr_err("topology_logical_(package/die)_id() returned a negative value");
return ERR_PTR(-EINVAL);
ret = -EINVAL;
goto err_free_package;
}
rp->lead_cpu = id;
if (!rapl_msrs_are_pkg_scope() && topology_max_dies_per_package() > 1)

View File

@ -42,6 +42,7 @@ config HIBERNATION
select CRC32
select CRYPTO
select CRYPTO_LZO
select CRYPTO_LZ4
help
Enable the suspend to disk (STD) functionality, which is usually
called "hibernation" in user interfaces. STD checkpoints the

View File

@ -392,23 +392,6 @@ static int create_image(int platform_mode)
return error;
}
static void shrink_shmem_memory(void)
{
struct sysinfo info;
unsigned long nr_shmem_pages, nr_freed_pages;
si_meminfo(&info);
nr_shmem_pages = info.sharedram; /* current page count used for shmem */
/*
* The intent is to reclaim all shmem pages. Though shrink_all_memory() can
* only reclaim about half of them, it's enough for creating the hibernation
* image.
*/
nr_freed_pages = shrink_all_memory(nr_shmem_pages);
pr_debug("requested to reclaim %lu shmem pages, actually freed %lu pages\n",
nr_shmem_pages, nr_freed_pages);
}
/**
* hibernation_snapshot - Quiesce devices and create a hibernation image.
* @platform_mode: If set, use platform driver to prepare for the transition.
@ -425,14 +408,9 @@ int hibernation_snapshot(int platform_mode)
if (error)
goto Close;
/* Preallocate image memory before shutting down devices. */
error = hibernate_preallocate_memory();
if (error)
goto Close;
error = freeze_kernel_threads();
if (error)
goto Cleanup;
goto Close;
if (hibernation_test(TEST_FREEZER)) {
@ -445,19 +423,13 @@ int hibernation_snapshot(int platform_mode)
}
error = dpm_prepare(PMSG_FREEZE);
if (error) {
dpm_complete(PMSG_RECOVER);
goto Thaw;
}
if (error)
goto Complete;
/*
* Device drivers may move lots of data to shmem in dpm_prepare(). The shmem
* pages will use lots of system memory, causing hibernation image creation
* fail due to insufficient free memory.
* This call is to force flush the shmem pages to swap disk and reclaim
* the system memory so that image creation can succeed.
*/
shrink_shmem_memory();
/* Preallocate image memory before shutting down devices. */
error = hibernate_preallocate_memory();
if (error)
goto Complete;
console_suspend_all();
pm_restrict_gfp_mask();
@ -492,10 +464,10 @@ int hibernation_snapshot(int platform_mode)
platform_end(platform_mode);
return error;
Complete:
dpm_complete(PMSG_RECOVER);
Thaw:
thaw_kernel_threads();
Cleanup:
swsusp_free();
goto Close;
}

View File

@ -570,29 +570,23 @@ struct crc_data {
wait_queue_head_t done; /* crc update done */
u32 *crc32; /* points to handle's crc32 */
size_t **unc_len; /* uncompressed lengths */
unsigned char **unc; /* uncompressed data */
unsigned char *unc[]; /* uncompressed data */
};
static struct crc_data *alloc_crc_data(int nr_threads)
{
struct crc_data *crc;
crc = kzalloc_obj(*crc);
crc = kzalloc_flex(*crc, unc, nr_threads);
if (!crc)
return NULL;
crc->unc = kcalloc(nr_threads, sizeof(*crc->unc), GFP_KERNEL);
if (!crc->unc)
goto err_free_crc;
crc->unc_len = kzalloc_objs(*crc->unc_len, nr_threads);
if (!crc->unc_len)
goto err_free_unc;
goto err_free_crc;
return crc;
err_free_unc:
kfree(crc->unc);
err_free_crc:
kfree(crc);
return NULL;
@ -607,7 +601,6 @@ static void free_crc_data(struct crc_data *crc)
kthread_stop(crc->thr);
kfree(crc->unc_len);
kfree(crc->unc);
kfree(crc);
}

View File

@ -3155,7 +3155,7 @@ class TestProps:
dev = f[0]
props[dev] = DevProps()
props[dev].altname = f[1]
if int(f[2]):
if len(f) > 2 and f[2] and int(f[2]):
props[dev].isasync = True
else:
props[dev].isasync = False