mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
ACPI: processor: idle: Reset cpuidle on C-state list changes
When a power notification event occurs, existing ACPI idle states may
become obsolete. The current implementation only performs a partial
update, leaving critical cpuidle parameters, like target_residency_ns
and exit_latency_ns, stale. Furthermore, per-CPU cpuidle_device data,
including last_residency_ns, states_usage, and the disable flag, are not
properly synchronized. Using these stale values leads to incorrect power
management decisions.
To ensure all parameters are correctly synchronized, modify the
notification handling logic:
1. Unregister all cpuidle_device instances to ensure a clean slate.
2. Unregister and re-register the ACPI idle driver. This forces the
framework to re-evaluate global state parameters and ensures the
driver state matches the new hardware power profile.
3. Re-initialize power information and re-register cpuidle_device for
all possible CPUs to restore functional idle management.
This complete reset ensures that the cpuidle framework and the underlying
ACPI states are perfectly synchronized after a power state change.
Signed-off-by: Huisong Li <lihuisong@huawei.com>
[ rjw: Subject rewrite ]
Link: https://patch.msgid.link/20260407081141.2493581-3-lihuisong@huawei.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
committed by
Rafael J. Wysocki
parent
a4c6c18e93
commit
07cba0de55
@@ -1307,37 +1307,42 @@ int acpi_processor_power_state_has_changed(struct acpi_processor *pr)
|
||||
*/
|
||||
|
||||
if (pr->id == 0 && cpuidle_get_driver() == &acpi_idle_driver) {
|
||||
|
||||
/* Protect against cpu-hotplug */
|
||||
cpus_read_lock();
|
||||
|
||||
/* Unregister cpuidle device of all CPUs */
|
||||
cpuidle_pause_and_lock();
|
||||
|
||||
/* Disable all cpuidle devices */
|
||||
for_each_online_cpu(cpu) {
|
||||
_pr = per_cpu(processors, cpu);
|
||||
if (!_pr || !_pr->flags.power_setup_done)
|
||||
continue;
|
||||
for_each_possible_cpu(cpu) {
|
||||
dev = per_cpu(acpi_cpuidle_device, cpu);
|
||||
cpuidle_disable_device(dev);
|
||||
}
|
||||
|
||||
/* Populate Updated C-state information */
|
||||
acpi_processor_get_power_info(pr);
|
||||
acpi_processor_setup_cpuidle_states(pr);
|
||||
|
||||
/* Enable all cpuidle devices */
|
||||
for_each_online_cpu(cpu) {
|
||||
_pr = per_cpu(processors, cpu);
|
||||
if (!_pr || !_pr->flags.power_setup_done)
|
||||
if (!_pr || !_pr->flags.power || !dev)
|
||||
continue;
|
||||
acpi_processor_get_power_info(_pr);
|
||||
if (_pr->flags.power) {
|
||||
dev = per_cpu(acpi_cpuidle_device, cpu);
|
||||
acpi_processor_setup_cpuidle_dev(_pr, dev);
|
||||
cpuidle_enable_device(dev);
|
||||
}
|
||||
|
||||
cpuidle_unregister_device_no_lock(dev);
|
||||
kfree(dev);
|
||||
_pr->flags.power = 0;
|
||||
}
|
||||
cpuidle_resume_and_unlock();
|
||||
|
||||
/*
|
||||
* Unregister ACPI idle driver, reinitialize ACPI idle states
|
||||
* and register ACPI idle driver again.
|
||||
*/
|
||||
acpi_processor_unregister_idle_driver();
|
||||
acpi_processor_register_idle_driver();
|
||||
|
||||
/*
|
||||
* Reinitialize power information of all CPUs and re-register
|
||||
* all cpuidle devices. Now idle states is ok to use, can enable
|
||||
* cpuidle of each CPU safely one by one.
|
||||
*/
|
||||
for_each_possible_cpu(cpu) {
|
||||
_pr = per_cpu(processors, cpu);
|
||||
if (!_pr)
|
||||
continue;
|
||||
acpi_processor_power_init(_pr);
|
||||
}
|
||||
|
||||
cpus_read_unlock();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user