Re: [PATCH v2 1/2] cpuidle: Extract and export no-lock variants of cpuidle_unregister_device

From: lihuisong (C)

Date: Wed Apr 08 2026 - 05:16:27 EST



On 4/7/2026 9:36 PM, Rafael J. Wysocki wrote:
On Tue, Apr 7, 2026 at 10:11 AM Huisong Li <lihuisong@xxxxxxxxxx> wrote:
The cpuidle_unregister_device() function always acquire the internal
cpuidle_lock (or pause/resume idle) during their execution.
However, in some power notification scenarios (e.g., when old idle
states may become unavailable), it is necessary to efficiently disable
cpuidle first, then remove and re-create all cpuidle devices for all
CPUs. To avoid frequent lock overhead and ensure atomicity across the
entire batch operation, the caller needs to hold the cpuidle_lock once
outside the loop.

To address this, extract the core logic into the new function
cpuidle_unregister_device_no_lock() and export it.

Signed-off-by: Huisong Li <lihuisong@xxxxxxxxxx>
---
drivers/cpuidle/cpuidle.c | 22 +++++++++++++++-------
include/linux/cpuidle.h | 2 ++
2 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index c7876e9e024f..1a55542efead 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -714,16 +714,12 @@ int cpuidle_register_device(struct cpuidle_device *dev)

EXPORT_SYMBOL_GPL(cpuidle_register_device);

-/**
- * cpuidle_unregister_device - unregisters a CPU's idle PM feature
- * @dev: the cpu
- */
-void cpuidle_unregister_device(struct cpuidle_device *dev)
+void cpuidle_unregister_device_no_lock(struct cpuidle_device *dev)
{
if (!dev || dev->registered == 0)
return;

- cpuidle_pause_and_lock();
+ lockdep_assert_held(&cpuidle_lock);

cpuidle_disable_device(dev);

@@ -732,10 +728,22 @@ void cpuidle_unregister_device(struct cpuidle_device *dev)
__cpuidle_unregister_device(dev);

cpuidle_coupled_unregister_device(dev);
+}
+EXPORT_SYMBOL_GPL(cpuidle_unregister_device_no_lock);
+
+/**
+ * cpuidle_unregister_device - unregisters a CPU's idle PM feature
+ * @dev: the cpu
+ */
+void cpuidle_unregister_device(struct cpuidle_device *dev)
+{
+ if (!dev || dev->registered == 0)
+ return;

+ cpuidle_pause_and_lock();
+ cpuidle_unregister_device_no_lock(dev);
cpuidle_resume_and_unlock();
}
-
EXPORT_SYMBOL_GPL(cpuidle_unregister_device);

/**
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 4073690504a7..2ead2d8c57e6 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -188,6 +188,7 @@ extern void cpuidle_driver_state_disabled(struct cpuidle_driver *drv, int idx,
extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
extern int cpuidle_register_device(struct cpuidle_device *dev);
extern void cpuidle_unregister_device(struct cpuidle_device *dev);
+extern void cpuidle_unregister_device_no_lock(struct cpuidle_device *dev);
extern int cpuidle_register(struct cpuidle_driver *drv,
const struct cpumask *const coupled_cpus);
extern void cpuidle_unregister(struct cpuidle_driver *drv);
@@ -226,6 +227,7 @@ static inline void cpuidle_unregister_driver(struct cpuidle_driver *drv) { }
static inline int cpuidle_register_device(struct cpuidle_device *dev)
{return -ENODEV; }
static inline void cpuidle_unregister_device(struct cpuidle_device *dev) { }
+static void cpuidle_unregister_device_no_lock(struct cpuidle_device *dev) {}
static inline int cpuidle_register(struct cpuidle_driver *drv,
const struct cpumask *const coupled_cpus)
{return -ENODEV; }
--
Both patches applied as 7.1 material, though I'm somewhat nervous
about removing sysfs entries under cpus_read_lock().
Thanks.

The sysfs entries has been removed using cpuidle_disable_device() before this change.
From this perspective, we don't change this behavor.🙂
Note that I've changed the subject of the second patch to "ACPI:
processor: idle: Reset cpuidle on C-state list changes".

Thanks!