Skip to content

Commit 07cba0d

Browse files
LiHuiSong1rafaeljw
authored andcommitted
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 <[email protected]> [ rjw: Subject rewrite ] Link: https://patch.msgid.link/[email protected] Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent a4c6c18 commit 07cba0d

1 file changed

Lines changed: 25 additions & 20 deletions

File tree

drivers/acpi/processor_idle.c

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,37 +1307,42 @@ int acpi_processor_power_state_has_changed(struct acpi_processor *pr)
13071307
*/
13081308

13091309
if (pr->id == 0 && cpuidle_get_driver() == &acpi_idle_driver) {
1310-
13111310
/* Protect against cpu-hotplug */
13121311
cpus_read_lock();
1313-
cpuidle_pause_and_lock();
13141312

1315-
/* Disable all cpuidle devices */
1316-
for_each_online_cpu(cpu) {
1313+
/* Unregister cpuidle device of all CPUs */
1314+
cpuidle_pause_and_lock();
1315+
for_each_possible_cpu(cpu) {
1316+
dev = per_cpu(acpi_cpuidle_device, cpu);
13171317
_pr = per_cpu(processors, cpu);
1318-
if (!_pr || !_pr->flags.power_setup_done)
1318+
if (!_pr || !_pr->flags.power || !dev)
13191319
continue;
1320-
dev = per_cpu(acpi_cpuidle_device, cpu);
1321-
cpuidle_disable_device(dev);
1320+
1321+
cpuidle_unregister_device_no_lock(dev);
1322+
kfree(dev);
1323+
_pr->flags.power = 0;
13221324
}
1325+
cpuidle_resume_and_unlock();
13231326

1324-
/* Populate Updated C-state information */
1325-
acpi_processor_get_power_info(pr);
1326-
acpi_processor_setup_cpuidle_states(pr);
1327+
/*
1328+
* Unregister ACPI idle driver, reinitialize ACPI idle states
1329+
* and register ACPI idle driver again.
1330+
*/
1331+
acpi_processor_unregister_idle_driver();
1332+
acpi_processor_register_idle_driver();
13271333

1328-
/* Enable all cpuidle devices */
1329-
for_each_online_cpu(cpu) {
1334+
/*
1335+
* Reinitialize power information of all CPUs and re-register
1336+
* all cpuidle devices. Now idle states is ok to use, can enable
1337+
* cpuidle of each CPU safely one by one.
1338+
*/
1339+
for_each_possible_cpu(cpu) {
13301340
_pr = per_cpu(processors, cpu);
1331-
if (!_pr || !_pr->flags.power_setup_done)
1341+
if (!_pr)
13321342
continue;
1333-
acpi_processor_get_power_info(_pr);
1334-
if (_pr->flags.power) {
1335-
dev = per_cpu(acpi_cpuidle_device, cpu);
1336-
acpi_processor_setup_cpuidle_dev(_pr, dev);
1337-
cpuidle_enable_device(dev);
1338-
}
1343+
acpi_processor_power_init(_pr);
13391344
}
1340-
cpuidle_resume_and_unlock();
1345+
13411346
cpus_read_unlock();
13421347
}
13431348

0 commit comments

Comments
 (0)