summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHuisong Li <lihuisong@huawei.com>2026-04-07 11:11:41 +0300
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2026-04-07 16:32:20 +0300
commit07cba0de5598a427cc8a7161202ebf4e79e692bd (patch)
tree07b32c4ef82c704006bf8a96d4230acdc58501ba
parenta4c6c18e93a1d24df9ab95794cef471c89daefe4 (diff)
downloadlinux-07cba0de5598a427cc8a7161202ebf4e79e692bd.tar.xz
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>
-rw-r--r--drivers/acpi/processor_idle.c45
1 files changed, 25 insertions, 20 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index c1cddb4a5887..ee5facccbe10 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -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();
- cpuidle_pause_and_lock();
- /* Disable all cpuidle devices */
- for_each_online_cpu(cpu) {
+ /* Unregister cpuidle device of all CPUs */
+ cpuidle_pause_and_lock();
+ for_each_possible_cpu(cpu) {
+ dev = per_cpu(acpi_cpuidle_device, cpu);
_pr = per_cpu(processors, cpu);
- if (!_pr || !_pr->flags.power_setup_done)
+ if (!_pr || !_pr->flags.power || !dev)
continue;
- dev = per_cpu(acpi_cpuidle_device, cpu);
- cpuidle_disable_device(dev);
+
+ cpuidle_unregister_device_no_lock(dev);
+ kfree(dev);
+ _pr->flags.power = 0;
}
+ cpuidle_resume_and_unlock();
- /* Populate Updated C-state information */
- acpi_processor_get_power_info(pr);
- acpi_processor_setup_cpuidle_states(pr);
+ /*
+ * Unregister ACPI idle driver, reinitialize ACPI idle states
+ * and register ACPI idle driver again.
+ */
+ acpi_processor_unregister_idle_driver();
+ acpi_processor_register_idle_driver();
- /* Enable all cpuidle devices */
- for_each_online_cpu(cpu) {
+ /*
+ * 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 || !_pr->flags.power_setup_done)
+ if (!_pr)
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);
- }
+ acpi_processor_power_init(_pr);
}
- cpuidle_resume_and_unlock();
+
cpus_read_unlock();
}