From: robherring2@gmail.com (Rob Herring)
To: linux-arm-kernel@lists.infradead.org
Subject: [RFC PATCH 1/8] ARM: Add commonly used cpuidle init code
Date: Tue, 06 Dec 2011 09:06:57 -0600 [thread overview]
Message-ID: <4EDE2F91.5090104@gmail.com> (raw)
In-Reply-To: <1323146291-10676-2-git-send-email-rob.lee@linaro.org>
On 12/05/2011 10:38 PM, Robert Lee wrote:
> Add commonly used cpuidle init code to avoid unecessary duplication.
>
> Signed-off-by: Robert Lee <rob.lee@linaro.org>
> ---
> arch/arm/common/Makefile | 1 +
> arch/arm/common/cpuidle.c | 132 ++++++++++++++++++++++++++++++++++++++++
> arch/arm/include/asm/cpuidle.h | 25 ++++++++
Why not move cpuidle drivers to drivers/idle/ ?
> 3 files changed, 158 insertions(+), 0 deletions(-)
> create mode 100644 arch/arm/common/cpuidle.c
> create mode 100644 arch/arm/include/asm/cpuidle.h
>
> diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
> index 6ea9b6f..0865f69 100644
> --- a/arch/arm/common/Makefile
> +++ b/arch/arm/common/Makefile
> @@ -17,3 +17,4 @@ obj-$(CONFIG_ARCH_IXP2000) += uengine.o
> obj-$(CONFIG_ARCH_IXP23XX) += uengine.o
> obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o
> obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o
> +obj-$(CONFIG_CPU_IDLE) += cpuidle.o
> diff --git a/arch/arm/common/cpuidle.c b/arch/arm/common/cpuidle.c
> new file mode 100644
> index 0000000..e9a46a3
> --- /dev/null
> +++ b/arch/arm/common/cpuidle.c
> @@ -0,0 +1,132 @@
> +/*
> + * Copyright 2011 Freescale Semiconductor, Inc.
> + * Copyright 2011 Linaro Ltd.
> + *
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +
> +/*
> + * This code performs provides some commonly used cpuidle setup functionality
> + * used by many ARM SoC platforms. Providing this functionality here
> + * reduces the duplication of this code for each ARM platform that uses it.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/io.h>
> +#include <linux/cpuidle.h>
> +#include <linux/hrtimer.h>
> +#include <linux/err.h>
> +#include <asm/cpuidle.h>
> +#include <asm/proc-fns.h>
> +
> +static struct cpuidle_device __percpu * arm_cpuidle_devices;
> +
> +static int (*mach_cpuidle)(struct cpuidle_device *dev,
> + struct cpuidle_driver *drv,
> + int index);
> +
> +static int arm_enter_idle(struct cpuidle_device *dev,
> + struct cpuidle_driver *drv, int index)
I think how this works is backwards. This function is only called if
there is a NULL enter function for a state, but mach_cpuidle is global.
Ideally, I want to call this function for every state, but call a
different mach_cpuidle function for each state. Yes, you could select a
specific function for each state within the mach_cpuidle function, but
that seems silly to make the per state function global and then have to
select a per state function again. And if many users are doing that,
then it belongs in the common code.
> +{
> + ktime_t time_start, time_end;
> +
> + local_irq_disable();
> + local_fiq_disable();
> +
> + time_start = ktime_get();
> +
> + index = mach_cpuidle(dev, drv, index);
> +
> + time_end = ktime_get();
> +
> + local_fiq_enable();
> + local_irq_enable();
> +
> + dev->last_residency =
> + (int)ktime_to_us(ktime_sub(time_end, time_start));
> +
> + return index;
> +}
> +
> +void arm_cpuidle_devices_uninit(void)
> +{
> + int cpu_id;
> + struct cpuidle_device *dev;
> +
> + for_each_possible_cpu(cpu_id) {
> + dev = per_cpu_ptr(arm_cpuidle_devices, cpu_id);
> + cpuidle_unregister_device(dev);
> + }
> +
> + free_percpu(arm_cpuidle_devices);
> + return;
Don't need return statement.
> +}
> +
> +int __init arm_cpuidle_init(struct cpuidle_driver *drv,
> + int (*common_enter)(struct cpuidle_device *dev,
> + struct cpuidle_driver *drv, int index),
> + void *driver_data[])
> +{
> + struct cpuidle_device *dev;
> + int i, cpu_id;
> +
> + if (drv == NULL) {
> + pr_err("%s: cpuidle_driver pointer NULL\n", __func__);
> + return -EINVAL;
> + }
> +
> + if (drv->state_count > CPUIDLE_STATE_MAX)
> + pr_err("%s: state count exceeds maximum\n", __func__);
return an error?
You can collapse these 2 parameter checks down to:
if (!drv || (drv->state_count > CPUIDLE_STATE_MAX))
> +
> + mach_cpuidle = common_enter;
> +
> + /* if state enter function not specified, use common_enter function */
> + for (i = 0; i < drv->state_count; i++) {
> + if (drv->states[i].enter == NULL) {
> + if (mach_cpuidle == NULL) {
Usually !mach_cpuidle is preferred for NULL checks. You can move this
check out of the loop.
> + pr_err("%s: 'enter' function pointer NULL\n",
> + __func__);
> + return -EINVAL;
> + } else
> + drv->states[i].enter = arm_enter_idle;
> + }
> + }
> +
> + if (cpuidle_register_driver(drv)) {
> + pr_err("%s: Failed to register cpuidle driver\n", __func__);
> + return -ENODEV;
> + }
> +
> + arm_cpuidle_devices = alloc_percpu(struct cpuidle_device);
> + if (arm_cpuidle_devices == NULL) {
> + cpuidle_unregister_driver(drv);
> + return -ENOMEM;
> + }
> +
> + /* initialize state data for each cpuidle_device */
> + for_each_possible_cpu(cpu_id) {
> +
> + dev = per_cpu_ptr(arm_cpuidle_devices, cpu_id);
> + dev->cpu = cpu_id;
> + dev->state_count = drv->state_count;
> +
> + if (driver_data)
> + for (i = 0; i < dev->state_count; i++) {
This would be more concise and less indentation:
for (i = 0; driver_data, i < dev->state_count; i++)
> + dev->states_usage[i].driver_data =
> + driver_data[i];
> + }
> +
> + if (cpuidle_register_device(dev)) {
> + pr_err("%s: Failed to register cpu %u\n",
> + __func__, cpu_id);
> + return -ENODEV;
Leaking memory here from alloc_percpu.
Also, need to unregister driver. It's usually cleaner to use goto's for
error clean-up.
Rob
next prev parent reply other threads:[~2011-12-06 15:06 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-12-06 4:38 [RFC PATCH 0/8] Add common ARM cpuidle init code Robert Lee
2011-12-06 4:38 ` [RFC PATCH 1/8] ARM: Add commonly used " Robert Lee
2011-12-06 11:47 ` Mark Brown
2011-12-08 17:34 ` Rob Lee
2011-12-09 8:25 ` Mark Brown
2011-12-06 15:06 ` Rob Herring [this message]
2011-12-08 21:46 ` Rob Lee
2011-12-09 13:54 ` Rob Herring
2011-12-09 15:55 ` Rob Lee
2011-12-09 19:48 ` Nicolas Pitre
2011-12-06 4:38 ` [RFC PATCH 2/8] ARM: at91: Replace init with new common ARM " Robert Lee
2011-12-06 4:38 ` [RFC PATCH 3/8] ARM: kirkwood: " Robert Lee
2011-12-06 4:38 ` [RFC PATCH 4/8] ARM: exynos: " Robert Lee
2011-12-06 4:38 ` [RFC PATCH 5/8] ARM: davinci: " Robert Lee
2011-12-06 4:38 ` [RFC PATCH 6/8] ARM: shmobile: " Robert Lee
2011-12-06 4:38 ` [RFC PATCH 7/8] ARM: imx: Add mx5 clock changes necessary for low power Robert Lee
2011-12-06 4:38 ` [RFC PATCH 8/8] ARM: imx: Add mx5 cpuidle implmentation Robert Lee
2011-12-08 14:56 ` [RFC PATCH 0/8] Add common ARM cpuidle init code Shawn Guo
2011-12-08 15:37 ` Arnd Bergmann
2012-01-03 14:54 ` Daniel Lezcano
2012-01-03 16:02 ` Arnd Bergmann
2012-01-04 9:17 ` Daniel Lezcano
2012-01-04 18:05 ` Rob Lee
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=4EDE2F91.5090104@gmail.com \
--to=robherring2@gmail.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.