diff options
| author | Huisong Li <lihuisong@huawei.com> | 2026-04-07 11:11:41 +0300 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2026-04-07 16:32:20 +0300 |
| commit | 07cba0de5598a427cc8a7161202ebf4e79e692bd (patch) | |
| tree | 07b32c4ef82c704006bf8a96d4230acdc58501ba | |
| parent | a4c6c18e93a1d24df9ab95794cef471c89daefe4 (diff) | |
| download | linux-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.c | 45 |
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(); } |
