From 11b3de1c03fa9f3b5d17e6d48050bc98b3704420 Mon Sep 17 00:00:00 2001 From: Huisong Li Date: Mon, 28 Jul 2025 15:06:11 +0800 Subject: [PATCH 01/13] ACPI: processor: idle: Fix memory leak when register cpuidle device failed The cpuidle device's memory is leaked when cpuidle device registration fails in acpi_processor_power_init(). Free it as appropriate. Fixes: 3d339dcbb56d ("cpuidle / ACPI : move cpuidle_device field out of the acpi_processor_power structure") Signed-off-by: Huisong Li Link: https://patch.msgid.link/20250728070612.1260859-2-lihuisong@huawei.com [ rjw: Changed the order of the new statements, added empty line after if () ] [ rjw: Changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_idle.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 2c2dc559e0f8..d0fc045a8d31 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1405,6 +1405,9 @@ int acpi_processor_power_init(struct acpi_processor *pr) 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++; From 149139ddcb99583fdec8d1eaf7dada41e5896101 Mon Sep 17 00:00:00 2001 From: Kaushlendra Kumar Date: Fri, 22 Aug 2025 11:49:46 +0530 Subject: [PATCH 02/13] ACPI: sysfs: Use ACPI_FREE() for freeing an ACPI object Since str_obj is allocated by ACPICA in acpi_evaluate_object_typed(), it should be free with ACPI_FREE() rather than with kfree(), so use the former instead of the latter for freeing it. Signed-off-by: Kaushlendra Kumar Link: https://patch.msgid.link/20250822061946.472594-1-kaushlendra.kumar@intel.com [ rjw: Subject and changelog rewrite ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/device_sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c index 3961fc47152c..cd199fbe4dc9 100644 --- a/drivers/acpi/device_sysfs.c +++ b/drivers/acpi/device_sysfs.c @@ -464,7 +464,7 @@ static ssize_t description_show(struct device *dev, buf[result++] = '\n'; - kfree(str_obj); + ACPI_FREE(str_obj); return result; } From 7a8c994cbb2db3c5335cee35fd486557f5aaf7e1 Mon Sep 17 00:00:00 2001 From: Huisong Li Date: Mon, 28 Jul 2025 15:06:12 +0800 Subject: [PATCH 03/13] ACPI: processor: idle: Optimize ACPI idle driver registration 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 Link: https://patch.msgid.link/20250728070612.1260859-3-lihuisong@huawei.com [ rjw: Added missing inline modifiers ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_driver.c | 3 ++ drivers/acpi/processor_idle.c | 65 +++++++++++++++++++++------------ include/acpi/processor.h | 8 ++++ 3 files changed, 53 insertions(+), 23 deletions(-) diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 65e779be64ff..bc9f58a02c1d 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -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); } diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index d0fc045a8d31..d8eb0b515188 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -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); } diff --git a/include/acpi/processor.h b/include/acpi/processor.h index d0eccbd920e5..360b673f05e5 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -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 */ From eb58738d1546bababc77392968ece9c595b4f737 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 13 Aug 2025 12:36:04 +0200 Subject: [PATCH 04/13] ACPI: processor: idle: Add module import namespace Add a new module import namespace called ACPI_PROCESSOR_IDLE for functions exported from the non-modular part of the ACPI processor driver to the modular part of it. Export acpi_processor_claim_cst_control() and acpi_processor_evaluate_cst() in that namespace to hide them from unrelated modules. They are also used by the intel_idle driver, but it is non-modular, so it can call them regardless of the way the symbols are exported. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/3376499.aeNJFYEL58@rafael.j.wysocki --- drivers/acpi/acpi_processor.c | 4 ++-- drivers/acpi/processor_idle.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 2a99f5eb6962..7ec1dc04fd11 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -815,7 +815,7 @@ bool acpi_processor_claim_cst_control(void) cst_control_claimed = true; return true; } -EXPORT_SYMBOL_GPL(acpi_processor_claim_cst_control); +EXPORT_SYMBOL_NS_GPL(acpi_processor_claim_cst_control, "ACPI_PROCESSOR_IDLE"); /** * acpi_processor_evaluate_cst - Evaluate the processor _CST control method. @@ -994,5 +994,5 @@ end: return ret; } -EXPORT_SYMBOL_GPL(acpi_processor_evaluate_cst); +EXPORT_SYMBOL_NS_GPL(acpi_processor_evaluate_cst, "ACPI_PROCESSOR_IDLE"); #endif /* CONFIG_ACPI_PROCESSOR_CSTATE */ diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index d8eb0b515188..0c8a88aa0553 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1453,3 +1453,5 @@ int acpi_processor_power_exit(struct acpi_processor *pr) pr->flags.power_setup_done = 0; return 0; } + +MODULE_IMPORT_NS("ACPI_PROCESSOR_IDLE"); From e4c628e91c6ab12f89500a023adfb030f737f3fd Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 13 Aug 2025 12:38:58 +0200 Subject: [PATCH 05/13] ACPI: processor: idle: Eliminate static variable flat_state_cnt Instead of using static variable flat_state_cnt to pass data between functions involved in the _LPI information processing, pass the current number of "flattened" idle states to flatten_lpi_states() and make it return the updated number of those states. At the same time, use a local variable called state_count to store the number of "flattened" idle states found so far in acpi_processor_get_lpi_info(). No intentional functional impact. Signed-off-by: Rafael J. Wysocki Reviewed-by: Sudeep Holla Tested-by: Sudeep Holla Acked-by: lihuisong@huawei.com Link: https://patch.msgid.link/10715991.nUPlyArG6x@rafael.j.wysocki --- drivers/acpi/processor_idle.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 0c8a88aa0553..5dacf41d7cc0 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -998,11 +998,6 @@ end: return ret; } -/* - * flat_state_cnt - the number of composite LPI states after the process of flattening - */ -static int flat_state_cnt; - /** * combine_lpi_states - combine local and parent LPI states to form a composite LPI state * @@ -1045,9 +1040,10 @@ static void stash_composite_state(struct acpi_lpi_states_array *curr_level, curr_level->composite_states[curr_level->composite_states_size++] = t; } -static int flatten_lpi_states(struct acpi_processor *pr, - struct acpi_lpi_states_array *curr_level, - struct acpi_lpi_states_array *prev_level) +static unsigned int flatten_lpi_states(struct acpi_processor *pr, + unsigned int flat_state_cnt, + struct acpi_lpi_states_array *curr_level, + struct acpi_lpi_states_array *prev_level) { int i, j, state_count = curr_level->size; struct acpi_lpi_state *p, *t = curr_level->entries; @@ -1087,7 +1083,7 @@ static int flatten_lpi_states(struct acpi_processor *pr, } kfree(curr_level->entries); - return 0; + return flat_state_cnt; } int __weak acpi_processor_ffh_lpi_probe(unsigned int cpu) @@ -1102,6 +1098,7 @@ static int acpi_processor_get_lpi_info(struct acpi_processor *pr) acpi_handle handle = pr->handle, pr_ahandle; struct acpi_device *d = NULL; struct acpi_lpi_states_array info[2], *tmp, *prev, *curr; + unsigned int state_count; /* make sure our architecture has support */ ret = acpi_processor_ffh_lpi_probe(pr->id); @@ -1114,14 +1111,13 @@ static int acpi_processor_get_lpi_info(struct acpi_processor *pr) if (!acpi_has_method(handle, "_LPI")) return -EINVAL; - flat_state_cnt = 0; prev = &info[0]; curr = &info[1]; handle = pr->handle; ret = acpi_processor_evaluate_lpi(handle, prev); if (ret) return ret; - flatten_lpi_states(pr, prev, NULL); + state_count = flatten_lpi_states(pr, 0, prev, NULL); status = acpi_get_parent(handle, &pr_ahandle); while (ACPI_SUCCESS(status)) { @@ -1143,18 +1139,19 @@ static int acpi_processor_get_lpi_info(struct acpi_processor *pr) break; /* flatten all the LPI states in this level of hierarchy */ - flatten_lpi_states(pr, curr, prev); + state_count = flatten_lpi_states(pr, state_count, curr, prev); tmp = prev, prev = curr, curr = tmp; status = acpi_get_parent(handle, &pr_ahandle); } - pr->power.count = flat_state_cnt; /* reset the index after flattening */ - for (i = 0; i < pr->power.count; i++) + for (i = 0; i < state_count; i++) pr->power.lpi_states[i].index = i; + pr->power.count = state_count; + /* Tell driver that _LPI is supported. */ pr->flags.has_lpi = 1; pr->flags.power = 1; From 4405a214df146775338a1e6232701a29024b82e1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 29 Aug 2025 16:27:48 +0200 Subject: [PATCH 06/13] ACPI: scan: Add Intel CVS ACPI HIDs to acpi_ignore_dep_ids[] Some x86/ACPI laptops with MIPI cameras have a INTC10DE or INTC10E0 ACPI device in the _DEP dependency list of the ACPI devices for the camera- sensors (which have flags.honor_deps set). These devices are for an Intel Vision CVS chip for which an out of tree driver is available [1]. The camera sensor works fine without a driver being loaded for this ACPI device on the 2 laptops this was tested on: ThinkPad X1 Carbon Gen 12 (Meteor Lake) ThinkPad X1 2-in-1 Gen 10 (Arrow Lake) For now add these HIDs to acpi_ignore_dep_ids[] so that acpi_dev_ready_for_enumeration() will return true once the other _DEP dependencies are met and an i2c_client for the camera sensor will get instantiated. Link: https://github.com/intel/vision-drivers/ [1] Signed-off-by: Hans de Goede Link: https://patch.msgid.link/20250829142748.21089-1-hansg@kernel.org Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index fb1fe9f3b1a3..9865faa996b0 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -845,6 +845,8 @@ static bool acpi_info_matches_ids(struct acpi_device_info *info, static const char * const acpi_ignore_dep_ids[] = { "PNP0D80", /* Windows-compatible System Power Management Controller */ "INT33BD", /* Intel Baytrail Mailbox Device */ + "INTC10DE", /* Intel CVS LNL */ + "INTC10E0", /* Intel CVS ARL */ "LATT2021", /* Lattice FW Update Client Driver */ NULL }; From 9d68320b2bca876278856fdc1e8684a7494dd069 Mon Sep 17 00:00:00 2001 From: Huisong Li Date: Fri, 5 Sep 2025 16:18:58 +0800 Subject: [PATCH 07/13] ACPI: processor: idle: Fix function defined but not used warning If CONFIG_ACPI_PROCESSOR_IDLE=n, acpi_processor_register_idle_driver() and acpi_processor_unregister_idle_driver() are never used and the empty stubs of them are not needed. Moreover, they cause the compiler to complain [1], so remove them. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202508300519.tZQHY6HA-lkp@intel.com/ [1] Fixes: 7a8c994cbb2d ("ACPI: processor: idle: Optimize ACPI idle driver registration") Signed-off-by: Huisong Li Link: https://patch.msgid.link/20250905081900.663869-2-lihuisong@huawei.com [ rjw: Changelog rewrite ] Signed-off-by: Rafael J. Wysocki --- include/acpi/processor.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 360b673f05e5..ff864c1cee3a 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -445,12 +445,6 @@ 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 */ From 2167bb92bdebb187e8b3a102987356ce981b77de Mon Sep 17 00:00:00 2001 From: Zihuan Zhang Date: Fri, 5 Sep 2025 21:24:09 +0800 Subject: [PATCH 08/13] ACPI: processor: thermal: Release policy references using __free() Replace the manual cpufreq_cpu_put() with __free(put_cpufreq_policy) for policy references. This reduces the risk of reference counting mistakes and aligns the code with the latest kernel style. No functional change intended. Signed-off-by: Zihuan Zhang Link: https://patch.msgid.link/20250905132413.1376220-3-zhangzihuan@kylinos.cn [ rjw: Subject and changelog edits, whitespace fixups ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_thermal.c | 52 +++++++++++++++++--------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 1219adb11ab9..c7b1dc5687ec 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -62,19 +62,14 @@ static int phys_package_first_cpu(int cpu) return 0; } -static int cpu_has_cpufreq(unsigned int cpu) +static bool cpu_has_cpufreq(unsigned int cpu) { - struct cpufreq_policy *policy; - if (!acpi_processor_cpufreq_init) return 0; - policy = cpufreq_cpu_get(cpu); - if (policy) { - cpufreq_cpu_put(policy); - return 1; - } - return 0; + struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu); + + return policy != NULL; } static int cpufreq_get_max_state(unsigned int cpu) @@ -93,12 +88,31 @@ static int cpufreq_get_cur_state(unsigned int cpu) return reduction_step(cpu); } +static bool cpufreq_update_thermal_limit(unsigned int cpu, struct acpi_processor *pr) +{ + unsigned long max_freq; + int ret; + + struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu); + if (!policy) + return false; + + max_freq = (policy->cpuinfo.max_freq * + (100 - reduction_step(cpu) * cpufreq_thermal_reduction_pctg)) / 100; + + ret = freq_qos_update_request(&pr->thermal_req, max_freq); + if (ret < 0) { + pr_warn("Failed to update thermal freq constraint: CPU%d (%d)\n", + pr->id, ret); + } + + return true; +} + static int cpufreq_set_cur_state(unsigned int cpu, int state) { - struct cpufreq_policy *policy; struct acpi_processor *pr; - unsigned long max_freq; - int i, ret; + int i; if (!cpu_has_cpufreq(cpu)) return 0; @@ -120,20 +134,8 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state) if (unlikely(!freq_qos_request_active(&pr->thermal_req))) continue; - policy = cpufreq_cpu_get(i); - if (!policy) + if (!cpufreq_update_thermal_limit(i, pr)) return -EINVAL; - - max_freq = (policy->cpuinfo.max_freq * - (100 - reduction_step(i) * cpufreq_thermal_reduction_pctg)) / 100; - - cpufreq_cpu_put(policy); - - ret = freq_qos_update_request(&pr->thermal_req, max_freq); - if (ret < 0) { - pr_warn("Failed to update thermal freq constraint: CPU%d (%d)\n", - pr->id, ret); - } } return 0; } From 5020d05b3476f3561377a4ab076d42fda00e3607 Mon Sep 17 00:00:00 2001 From: Huisong Li Date: Thu, 11 Sep 2025 19:24:06 +0800 Subject: [PATCH 09/13] ACPI: processor: Remove unused empty stubs of some functions Empty stubs are defined in processor.h for some functions provided by the ACPI processor idle driver, but those functions are only used in the main ACPI processor driver which requires the ACPI processor idle driver to be present (selecting CONFIG_ACPI_PROCESSOR causes CONFIG_ACPI_PROCESSOR_IDLE to be selected too automatically). This means that the empty stubs in question are not really necessary and if both CONFIG_ACPI_PROCESSOR and CONFIG_ACPI_PROCESSOR_IDLE are unset, the compiler complains that they are defined, but not used. Drop them to get rid of the compiler warning. Signed-off-by: Huisong Li Link: https://patch.msgid.link/20250911112408.1668431-2-lihuisong@huawei.com [ rjw: Subject and changelog rewrite ] Signed-off-by: Rafael J. Wysocki --- include/acpi/processor.h | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/include/acpi/processor.h b/include/acpi/processor.h index ff864c1cee3a..2976a6d0c54f 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -425,26 +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); -#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 bdf780fbcef5df4d365404a178e7f845a317b4e9 Mon Sep 17 00:00:00 2001 From: Huisong Li Date: Thu, 11 Sep 2025 19:24:07 +0800 Subject: [PATCH 10/13] ACPI: processor: idle: Rearrange declarations in header file Group all of the declarations of functions that belong to the ACPI processor idle driver together in one place in processor.h. While at it, drop the unnecessary extern modifier from the declaraions of two functions. Signed-off-by: Huisong Li Link: https://patch.msgid.link/20250911112408.1668431-3-lihuisong@huawei.com [ rjw: Subject and changelog rewrite ] Signed-off-by: Rafael J. Wysocki --- include/acpi/processor.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 2976a6d0c54f..6ee4a69412de 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -425,6 +425,8 @@ 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 */ @@ -447,11 +449,6 @@ 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 8a1b5d412cb405df402cdc59135655788fc59d0f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 18 Sep 2025 23:09:17 +0200 Subject: [PATCH 11/13] ACPI: processor: Update cpuidle driver check in __acpi_processor_start() Commit 7a8c994cbb2d ("ACPI: processor: idle: Optimize ACPI idle driver registration") moved the ACPI idle driver registration to acpi_processor_driver_init() and acpi_processor_power_init() does not register an idle driver any more. Accordingly, the cpuidle driver check in __acpi_processor_start() needs to be updated to avoid calling acpi_processor_power_init() without a cpuidle driver, in which case the registration of the cpuidle device in that function would lead to a NULL pointer dereference in __cpuidle_register_device(). Fixes: 7a8c994cbb2d ("ACPI: processor: idle: Optimize ACPI idle driver registration") Signed-off-by: Rafael J. Wysocki Reviewed-by: Mario Limonciello (AMD) Link: https://patch.msgid.link/5044465.31r3eYUQgx@rafael.j.wysocki [ rjw: Changelog update ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index bc9f58a02c1d..de17c1412678 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -166,7 +166,7 @@ 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"); - if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver) + if (cpuidle_get_driver() == &acpi_idle_driver) acpi_processor_power_init(pr); acpi_pss_perf_init(pr); From fbd401e95e569ad0307e4301012f2d8e1ec1ee98 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 18 Sep 2025 23:10:31 +0200 Subject: [PATCH 12/13] ACPI: processor: idle: Redefine two functions as void Notice that acpi_processor_power_init() and acpi_processor_power_exit() don't need to return any values because their callers don't check them anyway, so redefine those functions as void. While at it, rearrange the code in acpi_processor_power_init() to reduce the indentation level, get rid of a redundant local variable in that function, and rephrase a code comment in it. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mario Limonciello (AMD) --- drivers/acpi/processor_idle.c | 41 ++++++++++++++++------------------- include/acpi/processor.h | 4 ++-- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 5dacf41d7cc0..698d14c19587 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1400,47 +1400,45 @@ void acpi_processor_unregister_idle_driver(void) cpuidle_unregister_driver(&acpi_idle_driver); } -int acpi_processor_power_init(struct acpi_processor *pr) +void acpi_processor_power_init(struct acpi_processor *pr) { - int retval; struct cpuidle_device *dev; if (disabled_by_idle_boot_param()) - return 0; + return; acpi_processor_cstate_first_run_checks(); if (!acpi_processor_get_power_info(pr)) pr->flags.power_setup_done = 1; - if (pr->flags.power) { - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - per_cpu(acpi_cpuidle_device, pr->id) = dev; + if (!pr->flags.power) + return; - acpi_processor_setup_cpuidle_dev(pr, dev); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return; - /* Register per-cpu cpuidle_device. Cpuidle driver - * must already be registered before registering device - */ - retval = cpuidle_register_device(dev); - if (retval) { + per_cpu(acpi_cpuidle_device, pr->id) = dev; - per_cpu(acpi_cpuidle_device, pr->id) = NULL; - kfree(dev); - return 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); } - return 0; } -int acpi_processor_power_exit(struct acpi_processor *pr) +void 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 0; + return; if (pr->flags.power) { cpuidle_unregister_device(dev); @@ -1448,7 +1446,6 @@ int 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 6ee4a69412de..24fdaa3c2899 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 -int acpi_processor_power_init(struct acpi_processor *pr); -int acpi_processor_power_exit(struct acpi_processor *pr); +void acpi_processor_power_init(struct acpi_processor *pr); +void 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 559f2eacc8a23c7f44daac09d4f3efd958d497f2 Mon Sep 17 00:00:00 2001 From: Huisong Li Date: Tue, 23 Sep 2025 11:24:28 +0800 Subject: [PATCH 13/13] ACPI: processor: Do not expose global variable acpi_idle_driver Move the cpuidle driver check from __acpi_processor_start() to acpi_processor_power_init() which allows variable acpi_idle_driver to become static. No intentional functional impact. Signed-off-by: Huisong Li Link: https://patch.msgid.link/20250923032428.2656329-2-lihuisong@huawei.com [ rjw: Subject tweak, new changelog, adjustment of a new comment ] 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, 9 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index de17c1412678..5d824435b26b 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -166,8 +166,7 @@ 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"); - if (cpuidle_get_driver() == &acpi_idle_driver) - acpi_processor_power_init(pr); + 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 698d14c19587..22b051b94a86 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); -struct cpuidle_driver acpi_idle_driver = { +static struct cpuidle_driver acpi_idle_driver = { .name = "acpi_idle", .owner = THIS_MODULE, }; @@ -1404,6 +1404,13 @@ 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 24fdaa3c2899..7146a8e9e9c2 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -417,7 +417,6 @@ 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);