]> www.infradead.org Git - users/hch/misc.git/commitdiff
ACPI: processor: idle: Optimize ACPI idle driver registration
authorHuisong Li <lihuisong@huawei.com>
Mon, 28 Jul 2025 07:06:12 +0000 (15:06 +0800)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 2 Sep 2025 14:08:25 +0000 (16:08 +0200)
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().

Signed-off-by: Huisong Li <lihuisong@huawei.com>
Link: https://patch.msgid.link/20250728070612.1260859-3-lihuisong@huawei.com
[ rjw: Added missing inline modifiers ]
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..bc9f58a02c1db536e4e24c2f23206c4e72530d70 100644 (file)
@@ -263,6 +263,8 @@ 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);
@@ -301,6 +303,7 @@ 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 d0fc045a8d310c535dd78ae5b6e8488a2a619ed1..d8eb0b51518820e84ceba0d656cb53e2bfebae66 100644 (file)
@@ -1360,7 +1360,48 @@ 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.
+        * 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);
+}
 
 int acpi_processor_power_init(struct acpi_processor *pr)
 {
@@ -1375,22 +1416,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;
@@ -1403,14 +1429,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;
 }
@@ -1424,10 +1447,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..360b673f05e5759b4c611921b2ee98a56e90c5f1 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)
 {
@@ -443,6 +445,12 @@ static inline int acpi_processor_hotplug(struct acpi_processor *pr)
 {
        return -ENODEV;
 }
+static inline void acpi_processor_register_idle_driver(void)
+{
+}
+static inline void acpi_processor_unregister_idle_driver(void)
+{
+}
 #endif /* CONFIG_ACPI_PROCESSOR_IDLE */
 
 /* in processor_thermal.c */