Revert the ACPI idle driver registration lifecycle introduced by upstream commit 13ebeef6a1b9 ("ACPI: processor: idle: Optimize ACPI idle driver registration"). That change moved ACPI idle driver registration out of acpi_processor_power_init() and ahead of driver_register(). This breaks the established lifecycle on Xen dom0, where cpuidle is disabled during early architecture setup. Restore the 6.18.51 per-processor registration behavior. Keep unrelated 6.18.52 fixes, notably _LPI bounds validation and cpufreq notifier cleanup on initialization failure. diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 06589bf48..174dfb0ac 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -259,11 +259,9 @@ static int __init acpi_processor_driver_init(void) acpi_processor_ignore_ppc_init(); } - acpi_processor_register_idle_driver(); - result = driver_register(&acpi_processor_driver); if (result < 0) - goto unregister_idle_drv; + goto unregister_cpufreq; result = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "acpi/cpu-drv:online", @@ -289,9 +287,7 @@ static int __init acpi_processor_driver_init(void) err: driver_unregister(&acpi_processor_driver); -unregister_idle_drv: - acpi_processor_unregister_idle_driver(); - +unregister_cpufreq: if (acpi_processor_cpufreq_init) { cpufreq_unregister_notifier(&acpi_processor_notifier_block, CPUFREQ_POLICY_NOTIFIER); @@ -315,7 +311,6 @@ static void __exit acpi_processor_driver_exit(void) cpuhp_remove_state_nocalls(hp_online); cpuhp_remove_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD); driver_unregister(&acpi_processor_driver); - acpi_processor_unregister_idle_driver(); } module_init(acpi_processor_driver_init); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 5c6f736ba..7b4e948fa 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -831,13 +831,19 @@ static int acpi_processor_setup_cstates(struct acpi_processor *pr) return 0; } -static inline void acpi_processor_update_max_cstate(void) +static inline void acpi_processor_cstate_first_run_checks(void) { + static int first_run; + + if (first_run) + return; dmi_check_system(processor_power_dmi_table); max_cstate = acpi_processor_cstate_check(max_cstate); if (max_cstate < ACPI_C_STATES_MAX) pr_notice("processor limited to max C-state %d\n", max_cstate); + first_run++; + if (nocst) return; @@ -846,7 +852,7 @@ static inline void acpi_processor_update_max_cstate(void) #else static inline int disabled_by_idle_boot_param(void) { return 0; } -static inline void acpi_processor_update_max_cstate(void) { } +static inline void acpi_processor_cstate_first_run_checks(void) { } static int acpi_processor_get_cstate_info(struct acpi_processor *pr) { return -ENODEV; @@ -1365,59 +1371,7 @@ int acpi_processor_power_state_has_changed(struct acpi_processor *pr) return 0; } -void acpi_processor_register_idle_driver(void) -{ - struct acpi_processor *pr; - int ret = -ENODEV; - int cpu; - - /* - * If a cpuidle driver is already registered, there is no need to - * evaluate _CST or attempt to register the ACPI idle driver. - */ - if (cpuidle_get_driver()) { - pr_debug("cpuidle driver %pS already registered.\n", cpuidle_get_driver()); - return; - } - - acpi_processor_update_max_cstate(); - - /* - * ACPI idle driver is used by all possible CPUs. - * Use the processor power info of one in them to set up idle states. - * Note that the existing idle handler will be used on platforms that - * only support C1. - */ - for_each_possible_cpu(cpu) { - pr = per_cpu(processors, cpu); - if (!pr) - continue; - - ret = acpi_processor_get_power_info(pr); - if (!ret) { - pr->flags.power_setup_done = 1; - acpi_processor_setup_cpuidle_states(pr); - break; - } - } - - if (ret) { - pr_debug("No ACPI power information from any CPUs.\n"); - return; - } - - ret = cpuidle_register_driver(&acpi_idle_driver); - if (ret) { - pr_debug("register %s failed.\n", acpi_idle_driver.name); - return; - } - pr_debug("%s registered with cpuidle.\n", acpi_idle_driver.name); -} - -void acpi_processor_unregister_idle_driver(void) -{ - cpuidle_unregister_driver(&acpi_idle_driver); -} +static int acpi_processor_registered; int acpi_processor_power_init(struct acpi_processor *pr) { @@ -1427,10 +1381,27 @@ int acpi_processor_power_init(struct acpi_processor *pr) if (disabled_by_idle_boot_param()) return 0; + acpi_processor_cstate_first_run_checks(); + if (!acpi_processor_get_power_info(pr)) pr->flags.power_setup_done = 1; + /* + * Install the idle handler if processor power management is supported. + * Note that the existing idle handler is used on platforms that only + * support C1. + */ if (pr->flags.power) { + /* Register acpi_idle_driver if not already registered */ + if (!acpi_processor_registered) { + acpi_processor_setup_cpuidle_states(pr); + retval = cpuidle_register_driver(&acpi_idle_driver); + if (retval) + return retval; + pr_debug("%s registered with cpuidle\n", + acpi_idle_driver.name); + } + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; @@ -1443,11 +1414,14 @@ int acpi_processor_power_init(struct acpi_processor *pr) */ retval = cpuidle_register_device(dev); if (retval) { + if (acpi_processor_registered == 0) + cpuidle_unregister_driver(&acpi_idle_driver); per_cpu(acpi_cpuidle_device, pr->id) = NULL; kfree(dev); return retval; } + acpi_processor_registered++; } return 0; } @@ -1461,6 +1435,10 @@ int acpi_processor_power_exit(struct acpi_processor *pr) if (pr->flags.power) { cpuidle_unregister_device(dev); + acpi_processor_registered--; + if (acpi_processor_registered == 0) + cpuidle_unregister_driver(&acpi_idle_driver); + kfree(dev); } diff --git a/include/acpi/processor.h b/include/acpi/processor.h index ff864c1ce..d0eccbd92 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -423,8 +423,6 @@ int acpi_processor_power_init(struct acpi_processor *pr); int acpi_processor_power_exit(struct acpi_processor *pr); int acpi_processor_power_state_has_changed(struct acpi_processor *pr); int acpi_processor_hotplug(struct acpi_processor *pr); -void acpi_processor_register_idle_driver(void); -void acpi_processor_unregister_idle_driver(void); #else static inline int acpi_processor_power_init(struct acpi_processor *pr) {