From 34fa09c698d626b09f7824fe2c520a0a21a072b9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 25 Nov 2025 14:50:25 +0100 Subject: [PATCH 1/5] Revert "ACPI: processor: Do not expose global variable acpi_idle_driver" Revert commit 559f2eacc8a2 ACPI: processor: Do not expose global variable acpi_idle_driver" because it depends on a problematic one. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_driver.c | 3 ++- drivers/acpi/processor_idle.c | 9 +-------- include/acpi/processor.h | 1 + 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 5d824435b26b..de17c1412678 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -166,7 +166,8 @@ static int __acpi_processor_start(struct acpi_device *device) if (result && !IS_ENABLED(CONFIG_ACPI_CPU_FREQ_PSS)) dev_dbg(&device->dev, "CPPC data invalid or not present\n"); - acpi_processor_power_init(pr); + if (cpuidle_get_driver() == &acpi_idle_driver) + acpi_processor_power_init(pr); acpi_pss_perf_init(pr); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 22b051b94a86..698d14c19587 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -51,7 +51,7 @@ module_param(latency_factor, uint, 0644); static DEFINE_PER_CPU(struct cpuidle_device *, acpi_cpuidle_device); -static struct cpuidle_driver acpi_idle_driver = { +struct cpuidle_driver acpi_idle_driver = { .name = "acpi_idle", .owner = THIS_MODULE, }; @@ -1404,13 +1404,6 @@ void acpi_processor_power_init(struct acpi_processor *pr) { struct cpuidle_device *dev; - /* - * The code below only works if the current cpuidle driver is the ACPI - * idle driver. - */ - if (cpuidle_get_driver() != &acpi_idle_driver) - return; - if (disabled_by_idle_boot_param()) return; diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 7146a8e9e9c2..24fdaa3c2899 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -417,6 +417,7 @@ static inline void acpi_processor_throttling_init(void) {} #endif /* CONFIG_ACPI_CPU_FREQ_PSS */ /* in processor_idle.c */ +extern struct cpuidle_driver acpi_idle_driver; #ifdef CONFIG_ACPI_PROCESSOR_IDLE void acpi_processor_power_init(struct acpi_processor *pr); void acpi_processor_power_exit(struct acpi_processor *pr); From 66e600a26ee7d845d9434c3d60cef4bbf7dd3eb4 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 25 Nov 2025 14:53:33 +0100 Subject: [PATCH 2/5] Revert "ACPI: processor: idle: Redefine two functions as void" Revert commit fbd401e95e56 ("ACPI: processor: idle: Redefine two functions as void") because it depends on a problematic one. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_idle.c | 41 +++++++++++++++++++---------------- include/acpi/processor.h | 4 ++-- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 698d14c19587..5dacf41d7cc0 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1400,45 +1400,47 @@ void acpi_processor_unregister_idle_driver(void) cpuidle_unregister_driver(&acpi_idle_driver); } -void acpi_processor_power_init(struct acpi_processor *pr) +int acpi_processor_power_init(struct acpi_processor *pr) { + int retval; struct cpuidle_device *dev; if (disabled_by_idle_boot_param()) - return; + return 0; acpi_processor_cstate_first_run_checks(); if (!acpi_processor_get_power_info(pr)) pr->flags.power_setup_done = 1; - if (!pr->flags.power) - return; + if (pr->flags.power) { + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + per_cpu(acpi_cpuidle_device, pr->id) = dev; - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return; + acpi_processor_setup_cpuidle_dev(pr, dev); - per_cpu(acpi_cpuidle_device, pr->id) = dev; + /* Register per-cpu cpuidle_device. Cpuidle driver + * must already be registered before registering device + */ + retval = cpuidle_register_device(dev); + if (retval) { - acpi_processor_setup_cpuidle_dev(pr, dev); - - /* - * Register a cpuidle device for this CPU. The cpuidle driver using - * this device is expected to be registered. - */ - if (cpuidle_register_device(dev)) { - per_cpu(acpi_cpuidle_device, pr->id) = NULL; - kfree(dev); + per_cpu(acpi_cpuidle_device, pr->id) = NULL; + kfree(dev); + return retval; + } } + return 0; } -void acpi_processor_power_exit(struct acpi_processor *pr) +int acpi_processor_power_exit(struct acpi_processor *pr) { struct cpuidle_device *dev = per_cpu(acpi_cpuidle_device, pr->id); if (disabled_by_idle_boot_param()) - return; + return 0; if (pr->flags.power) { cpuidle_unregister_device(dev); @@ -1446,6 +1448,7 @@ void acpi_processor_power_exit(struct acpi_processor *pr) } pr->flags.power_setup_done = 0; + return 0; } MODULE_IMPORT_NS("ACPI_PROCESSOR_IDLE"); diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 24fdaa3c2899..6ee4a69412de 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -419,8 +419,8 @@ static inline void acpi_processor_throttling_init(void) {} /* in processor_idle.c */ extern struct cpuidle_driver acpi_idle_driver; #ifdef CONFIG_ACPI_PROCESSOR_IDLE -void acpi_processor_power_init(struct acpi_processor *pr); -void acpi_processor_power_exit(struct acpi_processor *pr); +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); From e6889323c2184c700428dd4b90a1c2c06b8ae51f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 25 Nov 2025 15:03:24 +0100 Subject: [PATCH 3/5] Revert "ACPI: processor: idle: Rearrange declarations in header file" Revert commit bdf780fbcef5 ("ACPI: processor: idle: Rearrange declarations in header file") because it depends on a problematic one. Signed-off-by: Rafael J. Wysocki --- include/acpi/processor.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 6ee4a69412de..2976a6d0c54f 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -425,8 +425,6 @@ 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); -int acpi_processor_ffh_lpi_probe(unsigned int cpu); -int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi); #endif /* CONFIG_ACPI_PROCESSOR_IDLE */ /* in processor_thermal.c */ @@ -449,6 +447,11 @@ static inline void acpi_thermal_cpufreq_exit(struct cpufreq_policy *policy) } #endif /* CONFIG_CPU_FREQ */ +#ifdef CONFIG_ACPI_PROCESSOR_IDLE +extern int acpi_processor_ffh_lpi_probe(unsigned int cpu); +extern int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi); +#endif + void acpi_processor_init_invariance_cppc(void); #endif From 1a8b3501821b608383f7c7aa0f24e2006681e2b5 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 25 Nov 2025 15:05:01 +0100 Subject: [PATCH 4/5] Revert "ACPI: processor: Remove unused empty stubs of some functions" Revert commit 5020d05b3476 ("ACPI: processor: Remove unused empty stubs of some functions") because it depends on a problematic one. Signed-off-by: Rafael J. Wysocki --- include/acpi/processor.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 2976a6d0c54f..ff864c1cee3a 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -425,6 +425,26 @@ 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) +{ + return -ENODEV; +} + +static inline int acpi_processor_power_exit(struct acpi_processor *pr) +{ + return -ENODEV; +} + +static inline int acpi_processor_power_state_has_changed(struct acpi_processor *pr) +{ + return -ENODEV; +} + +static inline int acpi_processor_hotplug(struct acpi_processor *pr) +{ + return -ENODEV; +} #endif /* CONFIG_ACPI_PROCESSOR_IDLE */ /* in processor_thermal.c */ From 43ff36c4a5a574ee83b4b0d3f3d74f09a3a8c2d3 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 25 Nov 2025 15:06:12 +0100 Subject: [PATCH 5/5] Revert "ACPI: processor: idle: Optimize ACPI idle driver registration" Revert commit 7a8c994cbb2d ("ACPI: processor: idle: Optimize ACPI idle driver registration") because it is reported to introduce a cpuidle regression leading to a kernel crash on a platform using the ACPI idle driver. Signed-off-by: Rafael J. Wysocki Reported-by: Borislav Petkov Tested-by: Borislav Petkov (AMD) Closes: https://lore.kernel.org/lkml/20251124200019.GIaSS5U9HhsWBotrQZ@fat_crate.local/ --- drivers/acpi/processor_driver.c | 3 -- drivers/acpi/processor_idle.c | 65 ++++++++++++--------------------- include/acpi/processor.h | 2 - 3 files changed, 23 insertions(+), 47 deletions(-) diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index de17c1412678..7644de24d2fa 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -263,8 +263,6 @@ static int __init acpi_processor_driver_init(void) if (result < 0) return result; - acpi_processor_register_idle_driver(); - result = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "acpi/cpu-drv:online", acpi_soft_cpu_online, NULL); @@ -303,7 +301,6 @@ static void __exit acpi_processor_driver_exit(void) cpuhp_remove_state_nocalls(hp_online); cpuhp_remove_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD); - acpi_processor_unregister_idle_driver(); driver_unregister(&acpi_processor_driver); } diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 5dacf41d7cc0..4166090db642 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1357,48 +1357,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; - - /* - * Acpi idle driver is used by all possible CPUs. - * Install the idle handler by the processor power info of one in them. - * Note that we use previously set idle handler will be used on - * platforms that only support C1. - */ - for_each_cpu(cpu, (struct cpumask *)cpu_possible_mask) { - 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) { @@ -1413,7 +1372,22 @@ int acpi_processor_power_init(struct acpi_processor *pr) 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 we use previously set idle handler will be 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; @@ -1426,11 +1400,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; } @@ -1444,6 +1421,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 ff864c1cee3a..d0eccbd920e5 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) {