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

From: Rafael J. Wysocki

Date: Tue Apr 07 2026 - 09:45:50 EST


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().

Note that I've changed the subject of the second patch to "ACPI:
processor: idle: Reset cpuidle on C-state list changes".

Thanks!