]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
Revert "ACPI: processor: idle: Optimize ACPI idle driver registration"
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 25 Nov 2025 14:06:12 +0000 (15:06 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 25 Nov 2025 15:08:06 +0000 (16:08 +0100)
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 <rafael.j.wysocki@intel.com>
Reported-by: Borislav Petkov <bp@alien8.de>
Tested-by: Borislav Petkov (AMD) <bp@alien8.de>
Closes: https://lore.kernel.org/lkml/20251124200019.GIaSS5U9HhsWBotrQZ@fat_crate.local/
drivers/acpi/processor_driver.c
drivers/acpi/processor_idle.c
include/acpi/processor.h

index de17c1412678091f55780653aacd05ad428d3649..7644de24d2faa4482cc10eb395166c5eca705807 100644 (file)
@@ -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);
 }
 
index 5dacf41d7cc0a0f8585936a01676ef56305b9300..4166090db64207518c1cffc69d6a884136036370 100644 (file)
@@ -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);
        }
 
index ff864c1cee3a4c3edf4be3a4f428bec2a86833e8..d0eccbd920e5cee2d7f1a55683d9530f1a13d5e2 100644 (file)
@@ -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)
 {