]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ACPI: processor: idle: Optimize ACPI idle driver registration
authorHuisong Li <lihuisong@huawei.com>
Tue, 23 Dec 2025 10:09:09 +0000 (18:09 +0800)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 9 Jan 2026 21:38:21 +0000 (22:38 +0100)
Currently, the ACPI idle driver is registered from within a CPU
hotplug callback. Although this didn't cause any functional issues,
this is questionable and confusing. And it is better to register
the cpuidle driver when all of the CPUs have been brought up.

So add a new function to initialize acpi_idle_driver based on the
power management information of an available CPU and register cpuidle
driver in acpi_processor_driver_init().

This commit has four changes under the commit 7a8c994cbb2d (ACPI:
processor: idle: Optimize ACPI idle driver registration):

 1) move acpi_processor_register_idle_driver() ahead of the
    driver_register().
 2) add acpi_processor_cstate_first_run_checks() before calling
    acpi_processor_get_power_info().
 3) squash the commit 9d68320b2bca (ACPI: processor: idle: Fix
    function defined but not used warning) into this change.
 4) use for_each_possible_cpu(cpu) to scan all possible cpus.

Signed-off-by: Huisong Li <lihuisong@huawei.com>
Tested-by: Borislav Petkov (AMD) <bp@alien8.de>
[ rjw: New comment edits, changelog tweak ]
Link: https://patch.msgid.link/20251223100914.2407069-2-lihuisong@huawei.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/processor_driver.c
drivers/acpi/processor_idle.c
include/acpi/processor.h

index 65e779be64ffcc6b728fc1b78df14435514c45db..311863e00ffd5eb080f22427f20fb4c733b7f518 100644 (file)
@@ -259,9 +259,11 @@ 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)
-               return result;
+               goto unregister_idle_drv;
 
        result = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
                                   "acpi/cpu-drv:online",
@@ -283,8 +285,13 @@ static int __init acpi_processor_driver_init(void)
        acpi_idle_rescan_dead_smt_siblings();
 
        return 0;
+
 err:
        driver_unregister(&acpi_processor_driver);
+
+unregister_idle_drv:
+       acpi_processor_unregister_idle_driver();
+
        return result;
 }
 
@@ -302,6 +309,7 @@ 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);
index 89f2f08b25549753c97402a74a14289eb031f0ce..0816356edb327f9ac84266f766d7cf746306c47b 100644 (file)
@@ -1347,7 +1347,49 @@ int acpi_processor_power_state_has_changed(struct acpi_processor *pr)
        return 0;
 }
 
-static int acpi_processor_registered;
+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.
+        * 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;
+
+               acpi_processor_cstate_first_run_checks();
+               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);
+}
 
 int acpi_processor_power_init(struct acpi_processor *pr)
 {
@@ -1362,22 +1404,7 @@ 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;
@@ -1390,14 +1417,11 @@ 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;
 }
@@ -1411,10 +1435,6 @@ 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 d0eccbd920e5cee2d7f1a55683d9530f1a13d5e2..ff864c1cee3a4c3edf4be3a4f428bec2a86833e8 100644 (file)
@@ -423,6 +423,8 @@ 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)
 {