linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: santosh.shilimkar@ti.com (Santosh Shilimkar)
To: linux-arm-kernel@lists.infradead.org
Subject: [V3 patch 06/19] cpuidle: make a single register function for all
Date: Thu, 18 Apr 2013 14:18:29 +0530	[thread overview]
Message-ID: <516FB35D.7000303@ti.com> (raw)
In-Reply-To: <1365770165-27096-7-git-send-email-daniel.lezcano@linaro.org>

On Friday 12 April 2013 06:05 PM, Daniel Lezcano wrote:
> The usual scheme to initialize a cpuidle driver on a SMP is:
> 
> 	cpuidle_register_driver(drv);
> 	for_each_possible_cpu(cpu) {
> 		device = &per_cpu(cpuidle_dev, cpu);
> 		cpuidle_register_device(device);
> 	}
> 
Not exactly related to $subject patch but the driver should
be registered after all devices has been registered to avoid
devices start using the idle state data as soon as it is
registered. In multi CPU system, this race can easily happen.

Current CPUIDLE core layer is also written with the assumption
that driver will be registered first and then the devices which
is not mandatory as per typical drive/device model.

May be you can fix that part while you are creating this common
wrapper.

> This code is duplicated in each cpuidle driver.
> 
> On UP systems, it is done this way:
> 
> 	cpuidle_register_driver(drv);
> 	device = &per_cpu(cpuidle_dev, cpu);
> 	cpuidle_register_device(device);
> 
> On UP, the macro 'for_each_cpu' does one iteration:
> 
> #define for_each_cpu(cpu, mask)                 \
>         for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
> 
> Hence, the initialization loop is the same for UP than SMP.
> 
> Beside, we saw different bugs / mis-initialization / return code unchecked in
> the different drivers, the code is duplicated including bugs. After fixing all
> these ones, it appears the initialization pattern is the same for everyone.
> 
> Please note, some drivers are doing dev->state_count = drv->state_count. This is
> not necessary because it is done by the cpuidle_enable_device function in the
> cpuidle framework. This is true, until you have the same states for all your
> devices. Otherwise, the 'low level' API should be used instead with the specific
> initialization for the driver.
> 
> Let's add a wrapper function doing this initialization with a cpumask parameter
> for the coupled idle states and use it for all the drivers.
> 
> That will save a lot of LOC, consolidate the code, and the modifications in the
> future could be done in a single place. Another benefit is the consolidation of
> the cpuidle_device variable which is now in the cpuidle framework and no longer
> spread accross the different arch specific drivers.
> 
s/accross/across

> Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
> ---
>  Documentation/cpuidle/driver.txt |    6 ++++
>  drivers/cpuidle/cpuidle.c        |   72 ++++++++++++++++++++++++++++++++++++++
>  include/linux/cpuidle.h          |    9 +++--
>  3 files changed, 85 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/cpuidle/driver.txt b/Documentation/cpuidle/driver.txt
> index 7a9e09e..1b0d81d 100644
> --- a/Documentation/cpuidle/driver.txt
> +++ b/Documentation/cpuidle/driver.txt
> @@ -15,11 +15,17 @@ has mechanisms in place to support actual entry-exit into CPU idle states.
>  cpuidle driver initializes the cpuidle_device structure for each CPU device
>  and registers with cpuidle using cpuidle_register_device.
>  
> +If all the idle states are the same, the wrapper function cpuidle_register
> +could be used instead.
> +
>  It can also support the dynamic changes (like battery <-> AC), by using
>  cpuidle_pause_and_lock, cpuidle_disable_device and cpuidle_enable_device,
>  cpuidle_resume_and_unlock.
>  
>  Interfaces:
> +extern int cpuidle_register(struct cpuidle_driver *drv,
> +                            const struct cpumask *const coupled_cpus);
> +extern int cpuidle_unregister(struct cpuidle_driver *drv);
>  extern int cpuidle_register_driver(struct cpuidle_driver *drv);
>  extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
>  extern int cpuidle_register_device(struct cpuidle_device *dev);
> diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
> index 0da795b..49e8d30 100644
> --- a/drivers/cpuidle/cpuidle.c
> +++ b/drivers/cpuidle/cpuidle.c
> @@ -24,6 +24,7 @@
>  #include "cpuidle.h"
>  
>  DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
> +DEFINE_PER_CPU(struct cpuidle_device, cpuidle_dev);
>  
>  DEFINE_MUTEX(cpuidle_lock);
>  LIST_HEAD(cpuidle_detected_devices);
> @@ -453,6 +454,77 @@ void cpuidle_unregister_device(struct cpuidle_device *dev)
>  
>  EXPORT_SYMBOL_GPL(cpuidle_unregister_device);
>  
> +/*
s/*/**
> + * cpuidle_unregister: unregister a driver and the devices. This function
> + * can be used only if the driver has been previously registered through
> + * the cpuidle_register function.
> + *
> + * @drv: a valid pointer to a struct cpuidle_driver
> + */
> +void cpuidle_unregister(struct cpuidle_driver *drv)
> +{
> +	int cpu;
> +	struct cpuidle_device *device;
> +
> +	for_each_possible_cpu(cpu) {
> +		device = &per_cpu(cpuidle_dev, cpu);
> +		cpuidle_unregister_device(device);
> +	}
> +
> +	cpuidle_unregister_driver(drv);
> +}
> +EXPORT_SYMBOL_GPL(cpuidle_unregister);
> +
> +/**
> + * cpuidle_register: registers the driver and the cpu devices with the
> + * coupled_cpus passed as parameter. This function is used for all common
> + * initialization pattern there are in the arch specific drivers. The
> + * devices is globally defined in this file.
> + *
> + * @drv         : a valid pointer to a struct cpuidle_driver
> + * @coupled_cpus: a cpumask for the coupled states
> + *
> + * Returns 0 on success, < 0 otherwise
> + */
> +int cpuidle_register(struct cpuidle_driver *drv,
> +		     const struct cpumask *const coupled_cpus)
> +{
> +	int ret, cpu;
> +	struct cpuidle_device *device;
> +
> +	ret = cpuidle_register_driver(drv);
> +	if (ret) {
> +		pr_err("failed to register cpuidle driver\n");
> +		return ret;
> +	}
> +
> +	for_each_possible_cpu(cpu) {
> +		device = &per_cpu(cpuidle_dev, cpu);
> +		device->cpu = cpu;
> +
> +#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
> +		/*
> +		 * On multiplatform for ARM, the coupled idle states could
> +		 * enabled in the kernel even if the cpuidle driver does not
> +		 * use it. Note, coupled_cpus is a struct copy.
> +		 */
> +		if (coupled_cpus)
> +			device->coupled_cpus = *coupled_cpus;
> +#endif
Can we get rid off the need of wrapping the code under CONFIG
marco in middle of function ?

> +		ret = cpuidle_register_device(device);
> +		if (!ret)
> +			continue;
> +
> +		pr_err("Failed to register cpuidle device for cpu%d\n", cpu);
> +
> +		cpuidle_unregister(drv);
> +		break;
> +	}
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(cpuidle_register);
> +
>  #ifdef CONFIG_SMP
>  
>  static void smp_callback(void *v)
> diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
> index 79e3811..3c86faa 100644
> --- a/include/linux/cpuidle.h
> +++ b/include/linux/cpuidle.h
> @@ -123,7 +123,9 @@ extern void cpuidle_driver_unref(void);
>  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 int cpuidle_register(struct cpuidle_driver *drv,
> +			    const struct cpumask *const coupled_cpus);
> +extern void cpuidle_unregister(struct cpuidle_driver *drv);
>  extern void cpuidle_pause_and_lock(void);
>  extern void cpuidle_resume_and_unlock(void);
>  extern void cpuidle_pause(void);
> @@ -148,7 +150,10 @@ 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 inline int cpuidle_register(struct cpuidle_driver *drv,
> +				   const struct cpumask *const coupled_cpus)
> +{return -ENODEV; }
> +static inline void cpuidle_unregister(struct cpuidle_driver *drv) { }
>  static inline void cpuidle_pause_and_lock(void) { }
>  static inline void cpuidle_resume_and_unlock(void) { }
>  static inline void cpuidle_pause(void) { }
> 

  parent reply	other threads:[~2013-04-18  8:48 UTC|newest]

Thread overview: 57+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-04-12 12:35 [V3 patch 00/19] cpuidle: code consolidation Daniel Lezcano
2013-04-12 12:35 ` [V3 patch 01/19] ARM: shmobile: cpuidle: remove shmobile_enter_wfi function Daniel Lezcano
2013-04-15  3:56   ` Simon Horman
2013-04-18  8:28   ` Santosh Shilimkar
2013-04-12 12:35 ` [V3 patch 02/19] ARM: shmobile: cpuidle: remove shmobile_enter_wfi prototype Daniel Lezcano
2013-04-15  3:56   ` Simon Horman
2013-04-18  8:30   ` Santosh Shilimkar
2013-04-18  8:56     ` Daniel Lezcano
2013-04-12 12:35 ` [V3 patch 03/19] ARM: OMAP3: remove cpuidle_wrap_enter Daniel Lezcano
2013-04-15 22:55   ` Kevin Hilman
2013-04-18  8:27   ` Santosh Shilimkar
2013-04-19 22:17   ` Kevin Hilman
2013-04-12 12:35 ` [V3 patch 04/19] cpuidle: remove en_core_tk_irqen flag Daniel Lezcano
2013-04-19 22:21   ` Kevin Hilman
2013-04-12 12:35 ` [V3 patch 05/19] ARM: ux500: cpuidle: replace for_each_online_cpu by for_each_possible_cpu Daniel Lezcano
2013-04-16 12:34   ` Linus Walleij
2013-04-18  8:38   ` Santosh Shilimkar
2013-04-12 12:35 ` [V3 patch 06/19] cpuidle: make a single register function for all Daniel Lezcano
2013-04-17  6:28   ` Daniel Lezcano
2013-04-18  8:48   ` Santosh Shilimkar [this message]
2013-04-23 13:43     ` Daniel Lezcano
2013-04-23 13:56       ` Santosh Shilimkar
2013-04-23 14:22         ` Daniel Lezcano
2013-04-23 15:07           ` Santosh Shilimkar
2013-04-23 15:21             ` Daniel Lezcano
2013-04-12 12:35 ` [V3 patch 07/19] ARM: ux500: cpuidle: use init/exit common routine Daniel Lezcano
2013-04-12 12:35 ` [V3 patch 08/19] ARM: at91: " Daniel Lezcano
2013-04-12 12:35 ` [V3 patch 09/19] ARM: OMAP3: " Daniel Lezcano
2013-04-18  8:49   ` Santosh Shilimkar
2013-04-19 22:19   ` Kevin Hilman
2013-04-12 12:35 ` [V3 patch 10/19] ARM: s3c64xx: " Daniel Lezcano
2013-04-22  6:32   ` Daniel Lezcano
2013-04-12 12:35 ` [V3 patch 11/19] ARM: tegra: " Daniel Lezcano
2013-04-12 12:35 ` [V3 patch 12/19] ARM: shmobile: " Daniel Lezcano
2013-04-15  3:56   ` Simon Horman
2013-04-12 12:35 ` [V3 patch 13/19] ARM: OMAP4: " Daniel Lezcano
2013-04-18  8:50   ` Santosh Shilimkar
2013-04-19 22:19   ` Kevin Hilman
2013-04-12 12:36 ` [V3 patch 14/19] ARM: tegra: cpuidle: use init/exit common routine for tegra2 Daniel Lezcano
2013-04-12 12:36 ` [V3 patch 15/19] ARM: tegra: cpuidle: use init/exit common routine for tegra3 Daniel Lezcano
2013-04-12 12:36 ` [V3 patch 16/19] ARM: calxeda: cpuidle: use init/exit common routine Daniel Lezcano
2013-04-12 12:36 ` [V3 patch 17/19] ARM: kirkwood: " Daniel Lezcano
2013-04-14 15:14   ` Andrew Lunn
2013-04-14 20:22     ` Daniel Lezcano
2013-04-22  7:01     ` Daniel Lezcano
2013-04-22 16:47       ` Andrew Lunn
2013-04-22 16:54         ` Daniel Lezcano
2013-04-12 12:36 ` [V3 patch 18/19] ARM: davinci: " Daniel Lezcano
2013-04-16  8:30   ` Sekhar Nori
2013-04-12 12:36 ` [V3 patch 19/19] ARM: imx: " Daniel Lezcano
2013-04-17  6:24   ` Daniel Lezcano
2013-04-17  7:15   ` Shawn Guo
2013-04-17  7:23     ` Daniel Lezcano
2013-04-17  7:39       ` Shawn Guo
2013-04-15 23:03 ` [V3 patch 00/19] cpuidle: code consolidation Kevin Hilman
2013-04-16  8:42   ` Daniel Lezcano
2013-04-19 22:44 ` Kevin Hilman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=516FB35D.7000303@ti.com \
    --to=santosh.shilimkar@ti.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).