Merge branches 'pm-cpufreq', 'pm-cpuidle', 'pm-runtime' and 'pm-sleep'

Merge assorted power management fixes for 7.4-rc1:

 - Fix potential out-of-bounds access in deferred reset in the cpufreq
   statistics code (Zhongqiu Han)

 - Cancel HWP notify work in the intel_pstate driver cleanup to prevent
   possible use-after-free from occurring (Tristan Madani)

 - Adjust state names and descriptions for ACPI _LPI idle states in the
   intel_idle driver to make them follow the driver's idle state naming
   convention (Rafael Wysocki)

 - Document the new pm_runtime_use_autosuspend() undo mechanism that
   triggers automatically on driver exit (Joshua Crofts)

 - Do not call suspend_ops->begin()/end() for suspend-to-idle to avoid
   driver confusion (Ovidiu Panait)

* pm-cpufreq:
  cpufreq: stats: Fix potential out-of-bounds access in deferred reset
  cpufreq: intel_pstate: cancel HWP notify work in driver cleanup

* pm-cpuidle:
  intel_idle: Adjust state names and descriptions for _LPI states

* pm-runtime:
  PM: runtime: clarify pm_runtime_use_autosuspend() undo mechanism

* pm-sleep:
  PM: suspend: Do not call suspend_ops->begin()/end() for s2idle
This commit is contained in:
Rafael J. Wysocki 2026-10-30 20:43:06 +01:00
7 changed files with 40 additions and 23 deletions

View File

@ -145,11 +145,13 @@ for the other idle state types (C2 and C3) the target residency value is 3 times
the exit latency (again, that is because it reflects the target residency to
exit latency ratio in the majority of cases for the processor models recognized
by ``intel_idle``). The name of the idle state (to be returned by the ``name``
idle state attribute in ``sysfs``) is either "Cx_LPI" (if it comes from ``_LPI``
processing) or "Cx_ACPI", where x is the index of that idle state in the final
list (note that the minimum value of x is 1, because 0 is reserved for the
"polling" state), and its target residency is based on the exit latency value.
All of the idle states in the final list are enabled by default in this case.
idle state attribute in ``sysfs``) either is equal to the state name value that
comes from ``_LPI`` processing (with the possible fallback to "Cx_LPI" if the
state name is not provided) or it is "Cx_ACPI", where x is the index of that
idle state in the final list (note that the minimum value of x is 1, because 0
is reserved for the "polling" state), and its target residency is based on the
exit latency value. All of the idle states in the final list are enabled by
default in this case.
.. _intel-idle-initialization:

View File

@ -425,11 +425,11 @@ but it also allows more flexibility in the handling of devices during the
removal of their drivers.
Drivers in ->remove() callback should undo the runtime PM changes done
in ->probe(). Usually this means calling pm_runtime_disable(),
pm_runtime_dont_use_autosuspend() etc. Alternatively, drivers can use
devm_pm_runtime_enable() during probe, which automatically takes care of
calling pm_runtime_disable() and pm_runtime_dont_use_autosuspend() upon driver
detachment.
in ->probe(). Usually this means calling pm_runtime_disable() etc.
Alternatively, drivers can use devm_pm_runtime_enable() during probe, which
automatically takes care of calling pm_runtime_disable() upon driver detachment.
Any pm_runtime_use_autosuspend() calls in a driver will be automatically undone
on driver exit.
The user space can effectively disallow the driver of the device to power manage
it at run time by changing the value of its /sys/devices/.../power/control

View File

@ -52,6 +52,10 @@ static void cpufreq_stats_reset_table(struct cpufreq_stats *stats)
* reset_pending accesses in cpufreq_stats_record_transition().
*/
smp_rmb();
if (stats->last_index == -1)
return;
cpufreq_stats_update(stats, READ_ONCE(stats->reset_time));
}

View File

@ -3436,6 +3436,8 @@ static void intel_pstate_driver_cleanup(void)
if (intel_pstate_driver == &intel_pstate)
intel_pstate_clear_update_util_hook(cpu);
intel_pstate_disable_hwp_interrupt(all_cpu_data[cpu]);
kfree(all_cpu_data[cpu]);
WRITE_ONCE(all_cpu_data[cpu], NULL);
}

View File

@ -1903,8 +1903,13 @@ static void __init intel_idle_init_cstates_acpi_lpi(struct cpuidle_driver *drv)
state = &drv->states[drv->state_count++];
scnprintf(state->name, CPUIDLE_NAME_LEN, "C%d_LPI", index + 1);
strscpy(state->desc, lpi_state->desc);
if (strlen(lpi_state->desc) > 0)
strscpy(state->name, lpi_state->desc);
else
scnprintf(state->name, CPUIDLE_NAME_LEN, "C%d_LPI", index + 1);
scnprintf(state->desc, CPUIDLE_DESC_LEN, "ACPI LPI MWAIT 0x%02llx",
lpi_state->address);
state->exit_latency = lpi_state->wake_latency;
state->target_residency = lpi_state->min_residency;
state->flags = MWAIT2flg(lpi_state->address);

View File

@ -855,9 +855,9 @@ static inline void pm_runtime_disable(struct device *dev)
* requested (or "autosuspend" will be handled as direct runtime-suspend for
* it).
*
* NOTE: It's important to undo this with pm_runtime_dont_use_autosuspend()
* at driver exit time unless your driver initially enabled pm_runtime
* with devm_pm_runtime_enable() (which handles it for you).
* NOTE: This is undone automatically with pm_runtime_dont_use_autosuspend() on
* driver exit regardless of whether a driver uses managed devm_* functions or
* not.
*/
static inline void pm_runtime_use_autosuspend(struct device *dev)
{

View File

@ -306,20 +306,24 @@ static void platform_resume_finish(suspend_state_t state)
static int platform_suspend_begin(suspend_state_t state)
{
if (state == PM_SUSPEND_TO_IDLE && s2idle_ops && s2idle_ops->begin)
return s2idle_ops->begin();
else if (suspend_ops && suspend_ops->begin)
if (state == PM_SUSPEND_TO_IDLE) {
if (s2idle_ops && s2idle_ops->begin)
return s2idle_ops->begin();
} else if (suspend_ops && suspend_ops->begin) {
return suspend_ops->begin(state);
else
return 0;
}
return 0;
}
static void platform_resume_end(suspend_state_t state)
{
if (state == PM_SUSPEND_TO_IDLE && s2idle_ops && s2idle_ops->end)
s2idle_ops->end();
else if (suspend_ops && suspend_ops->end)
if (state == PM_SUSPEND_TO_IDLE) {
if (s2idle_ops && s2idle_ops->end)
s2idle_ops->end();
} else if (suspend_ops && suspend_ops->end) {
suspend_ops->end();
}
}
static void platform_recover(suspend_state_t state)