This patch series moves various functionality duplicated in platform cpuidle drivers to the core cpuidle driver. Also, the platform irq disabling was removed as it appears that all calls into cpuidle_call_idle will have already called local_irq_disable().
Rafael,
Could you review this patchset and merge patch 1/9 once its ready? It seems pretty close to being acceptable. The get_maintainer script shows Len Brown as the cpuidle maintainer but I've been unable to get a response from him so far. If you are not the right person, could you suggest who I can make this request to? Thanks.
Note to platform maintainers:
Platform patches (2/9 to 9/9) in this patchset are not required to work with patch 1/9 but please review and push these platform changes as possible to allow this consolidation to occur.
Based on 3.3-rc5 plus recent exynos cpuidle patch (affects exynos cpuidle only): http://www.spinics.net/lists/linux-samsung-soc/msg09467.html
v6 submission tested successfully on Exynos (thanks Amit Kacchap) and OMAP3 (thanks Jean Pihet) platforms.
v6 submission can be found here: http://www.spinics.net/lists/arm-kernel/msg162018.html Changes since v6: * Made some struct whitespace alignment changes. * Fixed a coding style violation (thanks Jean Pihet) * Fixed a bug in davinci cpuidle (thanks Jean Pihet) * Corrected the common ARM cpuidle WFI state description to be ARM platform agnostic (thanks Kevin Hilman) * Fixed the problem causing x86 and PPC builds to fail (thanks Deepthi) * Re-added a line of code that was mistakenly removed (thanks Deepthi)
Robert Lee (9): cpuidle: Add common time keeping and irq enabling ARM: at91: Consolidate time keeping and irq enable ARM: exynos: Consolidate time keeping and irq enable ARM: kirkwood: Consolidate time keeping and irq enable ARM: davinci: Consolidate time keeping and irq enable ARM: omap: Consolidate OMAP3 time keeping and irq enable ARM: omap: Consolidate OMAP4 time keeping and irq enable ARM: shmobile: Consolidate time keeping and irq enable SH: shmobile: Consolidate time keeping and irq enable
arch/arm/include/asm/cpuidle.h | 22 +++++++++ arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/cpuidle.c | 21 ++++++++ arch/arm/mach-at91/cpuidle.c | 67 ++++++++++----------------- arch/arm/mach-davinci/cpuidle.c | 82 +++++++++++++------------------- arch/arm/mach-exynos/cpuidle.c | 53 ++------------------- arch/arm/mach-kirkwood/cpuidle.c | 72 ++++++++-------------------- arch/arm/mach-omap2/cpuidle34xx.c | 42 +++++++---------- arch/arm/mach-omap2/cpuidle44xx.c | 21 +------- arch/arm/mach-shmobile/cpuidle.c | 31 +++---------- arch/sh/kernel/cpu/shmobile/cpuidle.c | 10 +--- drivers/cpuidle/cpuidle.c | 79 +++++++++++++++++++++++++------ include/linux/cpuidle.h | 13 +++++- 13 files changed, 233 insertions(+), 282 deletions(-) create mode 100644 arch/arm/include/asm/cpuidle.h create mode 100644 arch/arm/kernel/cpuidle.c
Make necessary changes to implement time keeping and irq enabling in the core cpuidle code. This will allow the removal of these functionalities from various platform cpuidle implementations whose timekeeping and irq enabling follows the form in this common code.
Signed-off-by: Robert Lee rob.lee@linaro.org --- arch/arm/include/asm/cpuidle.h | 22 +++++++++++ arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/cpuidle.c | 21 +++++++++++ drivers/cpuidle/cpuidle.c | 79 ++++++++++++++++++++++++++++++++-------- include/linux/cpuidle.h | 13 ++++++- 5 files changed, 119 insertions(+), 18 deletions(-) create mode 100644 arch/arm/include/asm/cpuidle.h create mode 100644 arch/arm/kernel/cpuidle.c
diff --git a/arch/arm/include/asm/cpuidle.h b/arch/arm/include/asm/cpuidle.h new file mode 100644 index 0000000..165676e --- /dev/null +++ b/arch/arm/include/asm/cpuidle.h @@ -0,0 +1,22 @@ +#ifndef __ASM_ARM_CPUIDLE_H +#define __ASM_ARM_CPUIDLE_H + +#ifdef CONFIG_CPU_IDLE +extern int arm_cpuidle_simple_enter(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index); +#else +static inline int arm_cpuidle_simple_enter(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { return -ENODEV; } +#endif + +/* Common ARM WFI state */ +#define ARM_CPUIDLE_WFI_STATE {\ + .enter = arm_cpuidle_simple_enter,\ + .exit_latency = 1,\ + .target_residency = 1,\ + .flags = CPUIDLE_FLAG_TIME_VALID,\ + .name = "WFI",\ + .desc = "ARM WFI",\ +} + +#endif diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 43b740d..940c27f 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -21,7 +21,7 @@ obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += compat.o
obj-$(CONFIG_LEDS) += leds.o obj-$(CONFIG_OC_ETM) += etm.o - +obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_ISA_DMA_API) += dma.o obj-$(CONFIG_ARCH_ACORN) += ecard.o obj-$(CONFIG_FIQ) += fiq.o fiqasm.o diff --git a/arch/arm/kernel/cpuidle.c b/arch/arm/kernel/cpuidle.c new file mode 100644 index 0000000..89545f6 --- /dev/null +++ b/arch/arm/kernel/cpuidle.c @@ -0,0 +1,21 @@ +/* + * Copyright 2012 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 + */ + +#include <linux/cpuidle.h> +#include <asm/proc-fns.h> + +int arm_cpuidle_simple_enter(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + cpu_do_idle(); + + return index; +} diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 59f4261..56de5f7 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -53,6 +53,24 @@ static void cpuidle_kick_cpus(void) {}
static int __cpuidle_register_device(struct cpuidle_device *dev);
+static inline int cpuidle_enter(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + struct cpuidle_state *target_state = &drv->states[index]; + return target_state->enter(dev, drv, index); +} + +static inline int cpuidle_enter_tk(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + return cpuidle_wrap_enter(dev, drv, index, cpuidle_enter); +} + +typedef int (*cpuidle_enter_t)(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index); + +static cpuidle_enter_t cpuidle_enter_ops; + /** * cpuidle_idle_call - the main idle loop * @@ -63,7 +81,6 @@ int cpuidle_idle_call(void) { struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); struct cpuidle_driver *drv = cpuidle_get_driver(); - struct cpuidle_state *target_state; int next_state, entered_state;
if (off) @@ -92,12 +109,10 @@ int cpuidle_idle_call(void) return 0; }
- target_state = &drv->states[next_state]; - trace_power_start(POWER_CSTATE, next_state, dev->cpu); trace_cpu_idle(next_state, dev->cpu);
- entered_state = target_state->enter(dev, drv, next_state); + entered_state = cpuidle_enter_ops(dev, drv, next_state);
trace_power_end(dev->cpu); trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu); @@ -110,6 +125,8 @@ int cpuidle_idle_call(void) dev->states_usage[entered_state].time += (unsigned long long)dev->last_residency; dev->states_usage[entered_state].usage++; + } else { + dev->last_residency = 0; }
/* give the governor an opportunity to reflect on the outcome */ @@ -164,20 +181,29 @@ void cpuidle_resume_and_unlock(void)
EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
-#ifdef CONFIG_ARCH_HAS_CPU_RELAX -static int poll_idle(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int index) +/** + * cpuidle_wrap_enter - performs timekeeping and irqen around enter function + * @dev: pointer to a valid cpuidle_device object + * @drv: pointer to a valid cpuidle_driver object + * @index: index of the target cpuidle state. + */ +int cpuidle_wrap_enter(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index, + int (*enter)(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index)) { - ktime_t t1, t2; + ktime_t time_start, time_end; s64 diff;
- t1 = ktime_get(); + time_start = ktime_get(); + + index = enter(dev, drv, index); + + time_end = ktime_get(); + local_irq_enable(); - while (!need_resched()) - cpu_relax();
- t2 = ktime_get(); - diff = ktime_to_us(ktime_sub(t2, t1)); + diff = ktime_to_us(ktime_sub(time_end, time_start)); if (diff > INT_MAX) diff = INT_MAX;
@@ -186,6 +212,23 @@ static int poll_idle(struct cpuidle_device *dev, return index; }
+#ifdef CONFIG_ARCH_HAS_CPU_RELAX +static inline int __poll_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + while (!need_resched()) + cpu_relax(); + + return index; +} + +static int poll_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + return cpuidle_wrap_enter(dev, drv, index, + __poll_idle); +} + static void poll_idle_init(struct cpuidle_driver *drv) { struct cpuidle_state *state = &drv->states[0]; @@ -212,10 +255,11 @@ static void poll_idle_init(struct cpuidle_driver *drv) {} int cpuidle_enable_device(struct cpuidle_device *dev) { int ret, i; + struct cpuidle_driver *drv = cpuidle_get_driver();
if (dev->enabled) return 0; - if (!cpuidle_get_driver() || !cpuidle_curr_governor) + if (!drv || !cpuidle_curr_governor) return -EIO; if (!dev->state_count) return -EINVAL; @@ -226,13 +270,16 @@ int cpuidle_enable_device(struct cpuidle_device *dev) return ret; }
- poll_idle_init(cpuidle_get_driver()); + cpuidle_enter_ops = drv->en_core_tk_irqen ? + cpuidle_enter_tk : cpuidle_enter; + + poll_idle_init(drv);
if ((ret = cpuidle_add_state_sysfs(dev))) return ret;
if (cpuidle_curr_governor->enable && - (ret = cpuidle_curr_governor->enable(cpuidle_get_driver(), dev))) + (ret = cpuidle_curr_governor->enable(drv, dev))) goto fail_sysfs;
for (i = 0; i < dev->state_count; i++) { diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 712abcc..927db28 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -15,6 +15,7 @@ #include <linux/list.h> #include <linux/kobject.h> #include <linux/completion.h> +#include <linux/hrtimer.h>
#define CPUIDLE_STATE_MAX 8 #define CPUIDLE_NAME_LEN 16 @@ -122,6 +123,8 @@ struct cpuidle_driver { struct module *owner;
unsigned int power_specified:1; + /* set to 1 to use the core cpuidle time keeping (for all states). */ + unsigned int en_core_tk_irqen:1; struct cpuidle_state states[CPUIDLE_STATE_MAX]; int state_count; int safe_state_index; @@ -140,7 +143,10 @@ extern void cpuidle_pause_and_lock(void); extern void cpuidle_resume_and_unlock(void); extern int cpuidle_enable_device(struct cpuidle_device *dev); extern void cpuidle_disable_device(struct cpuidle_device *dev); - +extern int cpuidle_wrap_enter(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index, + int (*enter)(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index)); #else static inline void disable_cpuidle(void) { } static inline int cpuidle_idle_call(void) { return -ENODEV; } @@ -157,6 +163,11 @@ static inline void cpuidle_resume_and_unlock(void) { } static inline int cpuidle_enable_device(struct cpuidle_device *dev) {return -ENODEV; } static inline void cpuidle_disable_device(struct cpuidle_device *dev) { } +static inline int cpuidle_wrap_enter(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index, + int (*enter)(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index)) +{ return -ENODEV; }
#endif
Hi Rob,
On 03/01/2012 06:12 AM, Robert Lee wrote:
Make necessary changes to implement time keeping and irq enabling in the core cpuidle code. This will allow the removal of these functionalities from various platform cpuidle implementations whose timekeeping and irq enabling follows the form in this common code.
The generic cpuidle changes look good, but is there a reason as to why these changes are enabled only for ARM and not other archs ?
Signed-off-by: Robert Lee rob.lee@linaro.org
arch/arm/include/asm/cpuidle.h | 22 +++++++++++ arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/cpuidle.c | 21 +++++++++++ drivers/cpuidle/cpuidle.c | 79 ++++++++++++++++++++++++++++++++-------- include/linux/cpuidle.h | 13 ++++++- 5 files changed, 119 insertions(+), 18 deletions(-) create mode 100644 arch/arm/include/asm/cpuidle.h create mode 100644 arch/arm/kernel/cpuidle.c
diff --git a/arch/arm/include/asm/cpuidle.h b/arch/arm/include/asm/cpuidle.h new file mode 100644 index 0000000..165676e --- /dev/null +++ b/arch/arm/include/asm/cpuidle.h @@ -0,0 +1,22 @@ +#ifndef __ASM_ARM_CPUIDLE_H +#define __ASM_ARM_CPUIDLE_H
+#ifdef CONFIG_CPU_IDLE +extern int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index);
+#else +static inline int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index) { return -ENODEV; }
+#endif
+/* Common ARM WFI state */ +#define ARM_CPUIDLE_WFI_STATE {\
- .enter = arm_cpuidle_simple_enter,\
- .exit_latency = 1,\
- .target_residency = 1,\
- .flags = CPUIDLE_FLAG_TIME_VALID,\
- .name = "WFI",\
- .desc = "ARM WFI",\
+}
+#endif diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 43b740d..940c27f 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -21,7 +21,7 @@ obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += compat.o
obj-$(CONFIG_LEDS) += leds.o obj-$(CONFIG_OC_ETM) += etm.o
+obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_ISA_DMA_API) += dma.o obj-$(CONFIG_ARCH_ACORN) += ecard.o obj-$(CONFIG_FIQ) += fiq.o fiqasm.o diff --git a/arch/arm/kernel/cpuidle.c b/arch/arm/kernel/cpuidle.c new file mode 100644 index 0000000..89545f6 --- /dev/null +++ b/arch/arm/kernel/cpuidle.c @@ -0,0 +1,21 @@ +/*
- Copyright 2012 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:
- */
+#include <linux/cpuidle.h> +#include <asm/proc-fns.h>
+int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
+{
- cpu_do_idle();
- return index;
+} diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 59f4261..56de5f7 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -53,6 +53,24 @@ static void cpuidle_kick_cpus(void) {}
static int __cpuidle_register_device(struct cpuidle_device *dev);
+static inline int cpuidle_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
+{
- struct cpuidle_state *target_state = &drv->states[index];
- return target_state->enter(dev, drv, index);
+}
+static inline int cpuidle_enter_tk(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
+{
- return cpuidle_wrap_enter(dev, drv, index, cpuidle_enter);
+}
+typedef int (*cpuidle_enter_t)(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index);
+static cpuidle_enter_t cpuidle_enter_ops;
/**
- cpuidle_idle_call - the main idle loop
@@ -63,7 +81,6 @@ int cpuidle_idle_call(void) { struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); struct cpuidle_driver *drv = cpuidle_get_driver();
struct cpuidle_state *target_state; int next_state, entered_state;
if (off)
@@ -92,12 +109,10 @@ int cpuidle_idle_call(void) return 0; }
target_state = &drv->states[next_state];
trace_power_start(POWER_CSTATE, next_state, dev->cpu); trace_cpu_idle(next_state, dev->cpu);
entered_state = target_state->enter(dev, drv, next_state);
entered_state = cpuidle_enter_ops(dev, drv, next_state);
trace_power_end(dev->cpu); trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu);
@@ -110,6 +125,8 @@ int cpuidle_idle_call(void) dev->states_usage[entered_state].time += (unsigned long long)dev->last_residency; dev->states_usage[entered_state].usage++;
} else {
dev->last_residency = 0;
}
/* give the governor an opportunity to reflect on the outcome */
@@ -164,20 +181,29 @@ void cpuidle_resume_and_unlock(void)
EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
-#ifdef CONFIG_ARCH_HAS_CPU_RELAX -static int poll_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
+/**
- cpuidle_wrap_enter - performs timekeeping and irqen around enter function
- @dev: pointer to a valid cpuidle_device object
- @drv: pointer to a valid cpuidle_driver object
- @index: index of the target cpuidle state.
- */
+int cpuidle_wrap_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index,
int (*enter)(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index))
{
- ktime_t t1, t2;
- ktime_t time_start, time_end; s64 diff;
- t1 = ktime_get();
- time_start = ktime_get();
- index = enter(dev, drv, index);
- time_end = ktime_get();
- local_irq_enable();
while (!need_resched())
cpu_relax();
t2 = ktime_get();
diff = ktime_to_us(ktime_sub(t2, t1));
- diff = ktime_to_us(ktime_sub(time_end, time_start)); if (diff > INT_MAX) diff = INT_MAX;
@@ -186,6 +212,23 @@ static int poll_idle(struct cpuidle_device *dev, return index; }
+#ifdef CONFIG_ARCH_HAS_CPU_RELAX +static inline int __poll_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
+{
- while (!need_resched())
cpu_relax();
- return index;
+}
+static int poll_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
+{
- return cpuidle_wrap_enter(dev, drv, index,
__poll_idle);
+}
static void poll_idle_init(struct cpuidle_driver *drv) { struct cpuidle_state *state = &drv->states[0]; @@ -212,10 +255,11 @@ static void poll_idle_init(struct cpuidle_driver *drv) {} int cpuidle_enable_device(struct cpuidle_device *dev) { int ret, i;
struct cpuidle_driver *drv = cpuidle_get_driver();
if (dev->enabled) return 0;
- if (!cpuidle_get_driver() || !cpuidle_curr_governor)
- if (!drv || !cpuidle_curr_governor) return -EIO; if (!dev->state_count) return -EINVAL;
@@ -226,13 +270,16 @@ int cpuidle_enable_device(struct cpuidle_device *dev) return ret; }
- poll_idle_init(cpuidle_get_driver());
cpuidle_enter_ops = drv->en_core_tk_irqen ?
cpuidle_enter_tk : cpuidle_enter;
poll_idle_init(drv);
if ((ret = cpuidle_add_state_sysfs(dev))) return ret;
if (cpuidle_curr_governor->enable &&
(ret = cpuidle_curr_governor->enable(cpuidle_get_driver(), dev)))
(ret = cpuidle_curr_governor->enable(drv, dev)))
goto fail_sysfs;
for (i = 0; i < dev->state_count; i++) {
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 712abcc..927db28 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -15,6 +15,7 @@ #include <linux/list.h> #include <linux/kobject.h> #include <linux/completion.h> +#include <linux/hrtimer.h>
#define CPUIDLE_STATE_MAX 8 #define CPUIDLE_NAME_LEN 16 @@ -122,6 +123,8 @@ struct cpuidle_driver { struct module *owner;
unsigned int power_specified:1;
- /* set to 1 to use the core cpuidle time keeping (for all states). */
- unsigned int en_core_tk_irqen:1; struct cpuidle_state states[CPUIDLE_STATE_MAX]; int state_count; int safe_state_index;
@@ -140,7 +143,10 @@ extern void cpuidle_pause_and_lock(void); extern void cpuidle_resume_and_unlock(void); extern int cpuidle_enable_device(struct cpuidle_device *dev); extern void cpuidle_disable_device(struct cpuidle_device *dev);
+extern int cpuidle_wrap_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index,
int (*enter)(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index));
#else static inline void disable_cpuidle(void) { } static inline int cpuidle_idle_call(void) { return -ENODEV; } @@ -157,6 +163,11 @@ static inline void cpuidle_resume_and_unlock(void) { } static inline int cpuidle_enable_device(struct cpuidle_device *dev) {return -ENODEV; } static inline void cpuidle_disable_device(struct cpuidle_device *dev) { } +static inline int cpuidle_wrap_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index,
int (*enter)(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index))
+{ return -ENODEV; }
#endif
For the generic cpuidle changes Reviewed-by: Deepthi Dharwar deepthi@linux.vnet.ibm.com
Hello Deepthi,
On Wed, Feb 29, 2012 at 10:15 PM, Deepthi Dharwar deepthi@linux.vnet.ibm.com wrote:
Hi Rob,
On 03/01/2012 06:12 AM, Robert Lee wrote:
Make necessary changes to implement time keeping and irq enabling in the core cpuidle code. This will allow the removal of these functionalities from various platform cpuidle implementations whose timekeeping and irq enabling follows the form in this common code.
The generic cpuidle changes look good, but is there a reason as to why these changes are enabled only for ARM and not other archs ?
Besides ARM, this patchset also enables some of this new consolidation functionality on arch/SH and for archs that use the CONFIG_ARCH_HAS_CPU_RELAX (maybe x86 uses this?).
For the powerpc P-series, it could probably could be modified to use the consolidated timekeeping but I didn't feel comfortable making that change myself for a couple of reasons. First, the common wrapper also includes the local_irq_enable() call, but the p-series cpuidle code doesn't include this call, as instead, it relies on the local_irq_enable() call in the cpu_idle() function in arch/powerpc/kernel/idle.c. Is it OK to remove this local_irq_enable() once the wrapper is used? Second, is there any special coordination needed with the timekeeping functions and the mfspr() calls?
Looking at the intel and acpi cpuidle implementations, their current organization does seem to be able to use the common time keeping / irq enabling wrapper. Upon first glance, it appears that there are special timer/timekeeping requirements for x86 that aren't required by other platforms. But that may not be correct.
If you look back at v4 of this patch series, you'll see an attempt at a common timekeeping that could be used by x86 and acpi , but it causes other compromises that to me aren't worth the extra gain from a 100% common timekeeping / irq enable solution. I requested feedback/opinions on this issue after v4 but didn't hear anything about changes made to the intel or acpi implementations. So I continued on with the common wrapper direction from v3 when making v5.
Ultimately, even if the consolidated code only can be used by most and not all arch or platform cpuidle implementations, it still reduces some platform cpuidle fragmentation and duplicated code and hopefully improves the maintainability of the core cpuidle.
Enable core cpuidle timekeeping and irq enabling and remove that handling from this code.
Signed-off-by: Robert Lee rob.lee@linaro.org --- arch/arm/mach-at91/cpuidle.c | 67 +++++++++++++++--------------------------- 1 files changed, 24 insertions(+), 43 deletions(-)
diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c index a851e6c..d40b3f3 100644 --- a/arch/arm/mach-at91/cpuidle.c +++ b/arch/arm/mach-at91/cpuidle.c @@ -17,9 +17,10 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/cpuidle.h> -#include <asm/proc-fns.h> #include <linux/io.h> #include <linux/export.h> +#include <asm/proc-fns.h> +#include <asm/cpuidle.h>
#include "pm.h"
@@ -27,66 +28,46 @@
static DEFINE_PER_CPU(struct cpuidle_device, at91_cpuidle_device);
-static struct cpuidle_driver at91_idle_driver = { - .name = "at91_idle", - .owner = THIS_MODULE, -}; - /* Actual code that puts the SoC in different idle states */ static int at91_enter_idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { - struct timeval before, after; - int idle_time; u32 saved_lpr;
- local_irq_disable(); - do_gettimeofday(&before); - if (index == 0) - /* Wait for interrupt state */ - cpu_do_idle(); - else if (index == 1) { - asm("b 1f; .align 5; 1:"); - asm("mcr p15, 0, r0, c7, c10, 4"); /* drain write buffer */ - saved_lpr = sdram_selfrefresh_enable(); - cpu_do_idle(); - sdram_selfrefresh_disable(saved_lpr); - } - do_gettimeofday(&after); - local_irq_enable(); - idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + - (after.tv_usec - before.tv_usec); + __asm__("b 1f; .align 5; 1:\n" + " mcr p15, 0, r0, c7, c10, 4"); /* drain write buffer */ + + saved_lpr = sdram_selfrefresh_enable(); + cpu_do_idle(); + sdram_selfrefresh_disable(saved_lpr);
- dev->last_residency = idle_time; return index; }
+static struct cpuidle_driver at91_idle_driver = { + .name = "at91_idle", + .owner = THIS_MODULE, + .en_core_tk_irqen = 1, + .states[0] = ARM_CPUIDLE_WFI_STATE, + .states[1] = { + .enter = at91_enter_idle, + .exit_latency = 10, + .target_residency = 100000, + .flags = CPUIDLE_FLAG_TIME_VALID, + .name = "RAM_SR", + .desc = "WFI and DDR Self Refresh", + }, + .state_count = AT91_MAX_STATES, +}; + /* Initialize CPU idle by registering the idle states */ static int at91_init_cpuidle(void) { struct cpuidle_device *device; - struct cpuidle_driver *driver = &at91_idle_driver;
device = &per_cpu(at91_cpuidle_device, smp_processor_id()); device->state_count = AT91_MAX_STATES; - driver->state_count = AT91_MAX_STATES; - - /* Wait for interrupt state */ - driver->states[0].enter = at91_enter_idle; - driver->states[0].exit_latency = 1; - driver->states[0].target_residency = 10000; - driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID; - strcpy(driver->states[0].name, "WFI"); - strcpy(driver->states[0].desc, "Wait for interrupt"); - - /* Wait for interrupt and RAM self refresh state */ - driver->states[1].enter = at91_enter_idle; - driver->states[1].exit_latency = 10; - driver->states[1].target_residency = 10000; - driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID; - strcpy(driver->states[1].name, "RAM_SR"); - strcpy(driver->states[1].desc, "WFI and RAM Self Refresh");
cpuidle_register_driver(&at91_idle_driver);
Enable core cpuidle timekeeping and irq enabling and remove that handling from this code.
Signed-off-by: Robert Lee rob.lee@linaro.org --- arch/arm/mach-exynos/cpuidle.c | 53 ++++----------------------------------- 1 files changed, 6 insertions(+), 47 deletions(-)
diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index 9bf6743..7794fed 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -20,6 +20,7 @@ #include <asm/smp_scu.h> #include <asm/suspend.h> #include <asm/unified.h> +#include <asm/cpuidle.h> #include <mach/regs-pmu.h> #include <mach/pmu.h>
@@ -34,22 +35,12 @@
#define S5P_CHECK_AFTR 0xFCBA0D10
-static int exynos4_enter_idle(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index); static int exynos4_enter_lowpower(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index);
static struct cpuidle_state exynos4_cpuidle_set[] = { - [0] = { - .enter = exynos4_enter_idle, - .exit_latency = 1, - .target_residency = 100000, - .flags = CPUIDLE_FLAG_TIME_VALID, - .name = "C0", - .desc = "ARM clock gating(WFI)", - }, + [0] = ARM_CPUIDLE_WFI_STATE, [1] = { .enter = exynos4_enter_lowpower, .exit_latency = 300, @@ -63,8 +54,9 @@ static struct cpuidle_state exynos4_cpuidle_set[] = { static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device);
static struct cpuidle_driver exynos4_idle_driver = { - .name = "exynos4_idle", - .owner = THIS_MODULE, + .name = "exynos4_idle", + .owner = THIS_MODULE, + .en_core_tk_irqen = 1, };
/* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */ @@ -103,13 +95,8 @@ static int exynos4_enter_core0_aftr(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { - struct timeval before, after; - int idle_time; unsigned long tmp;
- local_irq_disable(); - do_gettimeofday(&before); - exynos4_set_wakeupmask();
/* Set value of power down register for aftr mode */ @@ -148,34 +135,6 @@ static int exynos4_enter_core0_aftr(struct cpuidle_device *dev, /* Clear wakeup state register */ __raw_writel(0x0, S5P_WAKEUP_STAT);
- do_gettimeofday(&after); - - local_irq_enable(); - idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + - (after.tv_usec - before.tv_usec); - - dev->last_residency = idle_time; - return index; -} - -static int exynos4_enter_idle(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index) -{ - struct timeval before, after; - int idle_time; - - local_irq_disable(); - do_gettimeofday(&before); - - cpu_do_idle(); - - do_gettimeofday(&after); - local_irq_enable(); - idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + - (after.tv_usec - before.tv_usec); - - dev->last_residency = idle_time; return index; }
@@ -190,7 +149,7 @@ static int exynos4_enter_lowpower(struct cpuidle_device *dev, new_index = drv->safe_state_index;
if (new_index == 0) - return exynos4_enter_idle(dev, drv, new_index); + return arm_cpuidle_simple_enter(dev, drv, new_index); else return exynos4_enter_core0_aftr(dev, drv, new_index); }
Enable core cpuidle timekeeping and irq enabling and remove that handling from this code.
Signed-off-by: Robert Lee rob.lee@linaro.org --- arch/arm/mach-kirkwood/cpuidle.c | 72 +++++++++++--------------------------- 1 files changed, 21 insertions(+), 51 deletions(-)
diff --git a/arch/arm/mach-kirkwood/cpuidle.c b/arch/arm/mach-kirkwood/cpuidle.c index 7088180..0f17109 100644 --- a/arch/arm/mach-kirkwood/cpuidle.c +++ b/arch/arm/mach-kirkwood/cpuidle.c @@ -20,77 +20,47 @@ #include <linux/io.h> #include <linux/export.h> #include <asm/proc-fns.h> +#include <asm/cpuidle.h> #include <mach/kirkwood.h>
#define KIRKWOOD_MAX_STATES 2
-static struct cpuidle_driver kirkwood_idle_driver = { - .name = "kirkwood_idle", - .owner = THIS_MODULE, -}; - -static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device); - /* Actual code that puts the SoC in different idle states */ static int kirkwood_enter_idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { - struct timeval before, after; - int idle_time; - - local_irq_disable(); - do_gettimeofday(&before); - if (index == 0) - /* Wait for interrupt state */ - cpu_do_idle(); - else if (index == 1) { - /* - * Following write will put DDR in self refresh. - * Note that we have 256 cycles before DDR puts it - * self in self-refresh, so the wait-for-interrupt - * call afterwards won't get the DDR from self refresh - * mode. - */ - writel(0x7, DDR_OPERATION_BASE); - cpu_do_idle(); - } - do_gettimeofday(&after); - local_irq_enable(); - idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + - (after.tv_usec - before.tv_usec); - - /* Update last residency */ - dev->last_residency = idle_time; + writel(0x7, DDR_OPERATION_BASE); + cpu_do_idle();
return index; }
+static struct cpuidle_driver kirkwood_idle_driver = { + .name = "kirkwood_idle", + .owner = THIS_MODULE, + .en_core_tk_irqen = 1, + .states[0] = ARM_CPUIDLE_WFI_STATE, + .states[1] = { + .enter = kirkwood_enter_idle, + .exit_latency = 10, + .target_residency = 100000, + .flags = CPUIDLE_FLAG_TIME_VALID, + .name = "DDR SR", + .desc = "WFI and DDR Self Refresh", + }, + .state_count = KIRKWOOD_MAX_STATES, +}; + +static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device); + /* Initialize CPU idle by registering the idle states */ static int kirkwood_init_cpuidle(void) { struct cpuidle_device *device; - struct cpuidle_driver *driver = &kirkwood_idle_driver;
device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id()); device->state_count = KIRKWOOD_MAX_STATES; - driver->state_count = KIRKWOOD_MAX_STATES; - - /* Wait for interrupt state */ - driver->states[0].enter = kirkwood_enter_idle; - driver->states[0].exit_latency = 1; - driver->states[0].target_residency = 10000; - driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID; - strcpy(driver->states[0].name, "WFI"); - strcpy(driver->states[0].desc, "Wait for interrupt"); - - /* Wait for interrupt and DDR self refresh state */ - driver->states[1].enter = kirkwood_enter_idle; - driver->states[1].exit_latency = 10; - driver->states[1].target_residency = 10000; - driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID; - strcpy(driver->states[1].name, "DDR SR"); - strcpy(driver->states[1].desc, "WFI and DDR Self Refresh");
cpuidle_register_driver(&kirkwood_idle_driver); if (cpuidle_register_device(device)) {
Enable core cpuidle timekeeping and irq enabling and remove that handling from this code.
Signed-off-by: Robert Lee rob.lee@linaro.org --- arch/arm/mach-davinci/cpuidle.c | 82 ++++++++++++++++----------------------- 1 files changed, 33 insertions(+), 49 deletions(-)
diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c index a30c7c5..93ae096 100644 --- a/arch/arm/mach-davinci/cpuidle.c +++ b/arch/arm/mach-davinci/cpuidle.c @@ -18,6 +18,7 @@ #include <linux/io.h> #include <linux/export.h> #include <asm/proc-fns.h> +#include <asm/cpuidle.h>
#include <mach/cpuidle.h> #include <mach/ddr2.h> @@ -30,12 +31,42 @@ struct davinci_ops { u32 flags; };
+/* Actual code that puts the SoC in different idle states */ +static int davinci_enter_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; + struct davinci_ops *ops = cpuidle_get_statedata(state_usage); + + if (ops && ops->enter) + ops->enter(ops->flags); + + index = cpuidle_wrap_enter(dev, drv, index, + arm_cpuidle_simple_enter); + + if (ops && ops->exit) + ops->exit(ops->flags); + + return index; +} + /* fields in davinci_ops.flags */ #define DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN BIT(0)
static struct cpuidle_driver davinci_idle_driver = { - .name = "cpuidle-davinci", - .owner = THIS_MODULE, + .name = "cpuidle-davinci", + .owner = THIS_MODULE, + .states[0] = ARM_CPUIDLE_WFI_STATE, + .states[1] = { + .enter = davinci_enter_idle, + .exit_latency = 10, + .target_residency = 100000, + .flags = CPUIDLE_FLAG_TIME_VALID, + .name = "DDR SR", + .desc = "WFI and DDR Self Refresh", + }, + .state_count = DAVINCI_CPUIDLE_MAX_STATES, };
static DEFINE_PER_CPU(struct cpuidle_device, davinci_cpuidle_device); @@ -77,41 +108,10 @@ static struct davinci_ops davinci_states[DAVINCI_CPUIDLE_MAX_STATES] = { }, };
-/* Actual code that puts the SoC in different idle states */ -static int davinci_enter_idle(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index) -{ - struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; - struct davinci_ops *ops = cpuidle_get_statedata(state_usage); - struct timeval before, after; - int idle_time; - - local_irq_disable(); - do_gettimeofday(&before); - - if (ops && ops->enter) - ops->enter(ops->flags); - /* Wait for interrupt state */ - cpu_do_idle(); - if (ops && ops->exit) - ops->exit(ops->flags); - - do_gettimeofday(&after); - local_irq_enable(); - idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + - (after.tv_usec - before.tv_usec); - - dev->last_residency = idle_time; - - return index; -} - static int __init davinci_cpuidle_probe(struct platform_device *pdev) { int ret; struct cpuidle_device *device; - struct cpuidle_driver *driver = &davinci_idle_driver; struct davinci_cpuidle_config *pdata = pdev->dev.platform_data;
device = &per_cpu(davinci_cpuidle_device, smp_processor_id()); @@ -123,27 +123,11 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev)
ddr2_reg_base = pdata->ddr2_ctlr_base;
- /* Wait for interrupt state */ - driver->states[0].enter = davinci_enter_idle; - driver->states[0].exit_latency = 1; - driver->states[0].target_residency = 10000; - driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID; - strcpy(driver->states[0].name, "WFI"); - strcpy(driver->states[0].desc, "Wait for interrupt"); - - /* Wait for interrupt and DDR self refresh state */ - driver->states[1].enter = davinci_enter_idle; - driver->states[1].exit_latency = 10; - driver->states[1].target_residency = 10000; - driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID; - strcpy(driver->states[1].name, "DDR SR"); - strcpy(driver->states[1].desc, "WFI and DDR Self Refresh"); if (pdata->ddr2_pdown) davinci_states[1].flags |= DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN; cpuidle_set_statedata(&device->states_usage[1], &davinci_states[1]);
device->state_count = DAVINCI_CPUIDLE_MAX_STATES; - driver->state_count = DAVINCI_CPUIDLE_MAX_STATES;
ret = cpuidle_register_driver(&davinci_idle_driver); if (ret) {
Use core cpuidle timekeeping and irqen wrapper and remove that handling from this code.
Signed-off-by: Robert Lee rob.lee@linaro.org --- arch/arm/mach-omap2/cpuidle34xx.c | 42 +++++++++++++++---------------------- 1 files changed, 17 insertions(+), 25 deletions(-)
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 464cffd..5358664 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -87,29 +87,14 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm, return 0; }
-/** - * omap3_enter_idle - Programs OMAP3 to enter the specified state - * @dev: cpuidle device - * @drv: cpuidle driver - * @index: the index of state to be entered - * - * Called from the CPUidle framework to program the device to the - * specified target state selected by the governor. - */ -static int omap3_enter_idle(struct cpuidle_device *dev, +static int __omap3_enter_idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { struct omap3_idle_statedata *cx = cpuidle_get_statedata(&dev->states_usage[index]); - struct timespec ts_preidle, ts_postidle, ts_idle; u32 mpu_state = cx->mpu_state, core_state = cx->core_state; - int idle_time; - - /* Used to keep track of the total time in idle */ - getnstimeofday(&ts_preidle);
- local_irq_disable(); local_fiq_disable();
pwrdm_set_next_pwrst(mpu_pd, mpu_state); @@ -148,22 +133,29 @@ static int omap3_enter_idle(struct cpuidle_device *dev, }
return_sleep_time: - getnstimeofday(&ts_postidle); - ts_idle = timespec_sub(ts_postidle, ts_preidle);
- local_irq_enable(); local_fiq_enable();
- idle_time = ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * \ - USEC_PER_SEC; - - /* Update cpuidle counters */ - dev->last_residency = idle_time; - return index; }
/** + * omap3_enter_idle - Programs OMAP3 to enter the specified state + * @dev: cpuidle device + * @drv: cpuidle driver + * @index: the index of state to be entered + * + * Called from the CPUidle framework to program the device to the + * specified target state selected by the governor. + */ +static inline int omap3_enter_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + return cpuidle_wrap_enter(dev, drv, index, __omap3_enter_idle); +} + +/** * next_valid_state - Find next valid C-state * @dev: cpuidle device * @drv: cpuidle driver
Enable core cpuidle timekeeping and irq enabling and remove that handling from this code.
Signed-off-by: Robert Lee rob.lee@linaro.org --- arch/arm/mach-omap2/cpuidle44xx.c | 21 +++------------------ 1 files changed, 3 insertions(+), 18 deletions(-)
diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index cfdbb86..e2ff9f6 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -62,16 +62,10 @@ static int omap4_enter_idle(struct cpuidle_device *dev, { struct omap4_idle_statedata *cx = cpuidle_get_statedata(&dev->states_usage[index]); - struct timespec ts_preidle, ts_postidle, ts_idle; u32 cpu1_state; - int idle_time; int new_state_idx; int cpu_id = smp_processor_id();
- /* Used to keep track of the total time in idle */ - getnstimeofday(&ts_preidle); - - local_irq_disable(); local_fiq_disable();
/* @@ -129,26 +123,17 @@ static int omap4_enter_idle(struct cpuidle_device *dev, if (index > 0) clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu_id);
- getnstimeofday(&ts_postidle); - ts_idle = timespec_sub(ts_postidle, ts_preidle); - - local_irq_enable(); local_fiq_enable();
- idle_time = ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * \ - USEC_PER_SEC; - - /* Update cpuidle counters */ - dev->last_residency = idle_time; - return index; }
DEFINE_PER_CPU(struct cpuidle_device, omap4_idle_dev);
struct cpuidle_driver omap4_idle_driver = { - .name = "omap4_idle", - .owner = THIS_MODULE, + .name = "omap4_idle", + .owner = THIS_MODULE, + .en_core_tk_irqen = 1, };
static inline void _fill_cstate(struct cpuidle_driver *drv,
Enable core cpuidle timekeeping and irq enabling and remove that handling from this code.
Signed-off-by: Robert Lee rob.lee@linaro.org --- arch/arm/mach-shmobile/cpuidle.c | 31 +++++++------------------------ 1 files changed, 7 insertions(+), 24 deletions(-)
diff --git a/arch/arm/mach-shmobile/cpuidle.c b/arch/arm/mach-shmobile/cpuidle.c index 1b23342..ca23b20 100644 --- a/arch/arm/mach-shmobile/cpuidle.c +++ b/arch/arm/mach-shmobile/cpuidle.c @@ -14,6 +14,7 @@ #include <linux/module.h> #include <linux/err.h> #include <asm/system.h> +#include <asm/cpuidle.h> #include <asm/io.h>
static void shmobile_enter_wfi(void) @@ -29,37 +30,19 @@ static int shmobile_cpuidle_enter(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { - ktime_t before, after; - - before = ktime_get(); - - local_irq_disable(); - local_fiq_disable(); - shmobile_cpuidle_modes[index]();
- local_irq_enable(); - local_fiq_enable(); - - after = ktime_get(); - dev->last_residency = ktime_to_ns(ktime_sub(after, before)) >> 10; - return index; }
static struct cpuidle_device shmobile_cpuidle_dev; static struct cpuidle_driver shmobile_cpuidle_driver = { - .name = "shmobile_cpuidle", - .owner = THIS_MODULE, - .states[0] = { - .name = "C1", - .desc = "WFI", - .exit_latency = 1, - .target_residency = 1 * 2, - .flags = CPUIDLE_FLAG_TIME_VALID, - }, - .safe_state_index = 0, /* C1 */ - .state_count = 1, + .name = "shmobile_cpuidle", + .owner = THIS_MODULE, + .en_core_tk_irqen = 1, + .states[0] = ARM_CPUIDLE_WFI_STATE, + .safe_state_index = 0, /* C1 */ + .state_count = 1, };
void (*shmobile_cpuidle_setup)(struct cpuidle_driver *drv);
Enable core cpuidle timekeeping and irq enabling and remove that handling from this code.
Signed-off-by: Robert Lee rob.lee@linaro.org --- arch/sh/kernel/cpu/shmobile/cpuidle.c | 10 +++------- 1 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c index 6d62eb4..1ddc876 100644 --- a/arch/sh/kernel/cpu/shmobile/cpuidle.c +++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c @@ -29,7 +29,6 @@ static int cpuidle_sleep_enter(struct cpuidle_device *dev, int index) { unsigned long allowed_mode = SUSP_SH_SLEEP; - ktime_t before, after; int requested_state = index; int allowed_state; int k; @@ -47,19 +46,16 @@ static int cpuidle_sleep_enter(struct cpuidle_device *dev, */ k = min_t(int, allowed_state, requested_state);
- before = ktime_get(); sh_mobile_call_standby(cpuidle_mode[k]); - after = ktime_get(); - - dev->last_residency = (int)ktime_to_ns(ktime_sub(after, before)) >> 10;
return k; }
static struct cpuidle_device cpuidle_dev; static struct cpuidle_driver cpuidle_driver = { - .name = "sh_idle", - .owner = THIS_MODULE, + .name = "sh_idle", + .owner = THIS_MODULE, + .en_core_tk_irqen = 1, };
void sh_mobile_setup_cpuidle(void)
On Wed, Feb 29, 2012 at 6:42 PM, Robert Lee rob.lee@linaro.org wrote:
This patch series moves various functionality duplicated in platform cpuidle drivers to the core cpuidle driver. Also, the platform irq disabling was removed as it appears that all calls into cpuidle_call_idle will have already called local_irq_disable().
I'm told that I forgot to add the Acks from the previous v6 to this version:
Acked-by: Jean Pihet j-pihet@ti.com (v6) Tested-by: Jean Pihet j-pihet@ti.com (v6, omap3) Tested-by: Amit Daniel amit.kachhap@linaro.org (v6, Exynos4) For the generic cpuidle changes: Reviewed-by: Deepthi Dharwar deepthi@linux.vnet.ibm.com
If anyone sees other omissions or has any suggested changes or improvements in my patch submissions semantics, please let me know.
Thanks, Rob
Rafael,
Could you review this patchset and merge patch 1/9 once its ready? It seems pretty close to being acceptable. The get_maintainer script shows Len Brown as the cpuidle maintainer but I've been unable to get a response from him so far. If you are not the right person, could you suggest who I can make this request to? Thanks.
Note to platform maintainers:
Platform patches (2/9 to 9/9) in this patchset are not required to work with patch 1/9 but please review and push these platform changes as possible to allow this consolidation to occur.
Based on 3.3-rc5 plus recent exynos cpuidle patch (affects exynos cpuidle only): http://www.spinics.net/lists/linux-samsung-soc/msg09467.html
v6 submission tested successfully on Exynos (thanks Amit Kacchap) and OMAP3 (thanks Jean Pihet) platforms.
v6 submission can be found here: http://www.spinics.net/lists/arm-kernel/msg162018.html Changes since v6:
- Made some struct whitespace alignment changes.
- Fixed a coding style violation (thanks Jean Pihet)
- Fixed a bug in davinci cpuidle (thanks Jean Pihet)
- Corrected the common ARM cpuidle WFI state description to be ARM platform
agnostic (thanks Kevin Hilman)
- Fixed the problem causing x86 and PPC builds to fail (thanks Deepthi)
- Re-added a line of code that was mistakenly removed (thanks Deepthi)
Robert Lee (9): cpuidle: Add common time keeping and irq enabling ARM: at91: Consolidate time keeping and irq enable ARM: exynos: Consolidate time keeping and irq enable ARM: kirkwood: Consolidate time keeping and irq enable ARM: davinci: Consolidate time keeping and irq enable ARM: omap: Consolidate OMAP3 time keeping and irq enable ARM: omap: Consolidate OMAP4 time keeping and irq enable ARM: shmobile: Consolidate time keeping and irq enable SH: shmobile: Consolidate time keeping and irq enable
arch/arm/include/asm/cpuidle.h | 22 +++++++++ arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/cpuidle.c | 21 ++++++++ arch/arm/mach-at91/cpuidle.c | 67 ++++++++++----------------- arch/arm/mach-davinci/cpuidle.c | 82 +++++++++++++------------------- arch/arm/mach-exynos/cpuidle.c | 53 ++------------------- arch/arm/mach-kirkwood/cpuidle.c | 72 ++++++++-------------------- arch/arm/mach-omap2/cpuidle34xx.c | 42 +++++++---------- arch/arm/mach-omap2/cpuidle44xx.c | 21 +------- arch/arm/mach-shmobile/cpuidle.c | 31 +++---------- arch/sh/kernel/cpu/shmobile/cpuidle.c | 10 +--- drivers/cpuidle/cpuidle.c | 79 +++++++++++++++++++++++++------ include/linux/cpuidle.h | 13 +++++- 13 files changed, 233 insertions(+), 282 deletions(-) create mode 100644 arch/arm/include/asm/cpuidle.h create mode 100644 arch/arm/kernel/cpuidle.c
On 03/01/2012 09:57 PM, Rob Lee wrote:
On Wed, Feb 29, 2012 at 6:42 PM, Robert Leerob.lee@linaro.org wrote:
This patch series moves various functionality duplicated in platform cpuidle drivers to the core cpuidle driver. Also, the platform irq disabling was removed as it appears that all calls into cpuidle_call_idle will have already called local_irq_disable().
I'm told that I forgot to add the Acks from the previous v6 to this version:
Acked-by: Jean Pihetj-pihet@ti.com (v6) Tested-by: Jean Pihetj-pihet@ti.com (v6, omap3) Tested-by: Amit Danielamit.kachhap@linaro.org (v6, Exynos4) For the generic cpuidle changes: Reviewed-by: Deepthi Dharwardeepthi@linux.vnet.ibm.com
Reviewed-by: Daniel Lezcano daniel.lezcano@linaro.org
Robert Lee rob.lee@linaro.org writes:
This patch series moves various functionality duplicated in platform cpuidle drivers to the core cpuidle driver. Also, the platform irq disabling was removed as it appears that all calls into cpuidle_call_idle will have already called local_irq_disable().
Reviewed-by: Kevin Hilman khilman@ti.com
Hello Stephen,
The following changes since commit 192cfd58774b4d17b2fe8bdc77d89c2ef4e0591d:
Linux 3.3-rc6 (2012-03-03 17:08:09 -0800)
are available in the git repository at: git://git.linaro.org/people/rob_lee/linux.git cpuidle_consol_pull
Robert Lee (8): cpuidle: Add common time keeping and irq enabling ARM: at91: Consolidate time keeping and irq enable ARM: kirkwood: Consolidate time keeping and irq enable ARM: davinci: Consolidate time keeping and irq enable ARM: omap: Consolidate OMAP3 time keeping and irq enable ARM: omap: Consolidate OMAP4 time keeping and irq enable ARM: shmobile: Consolidate time keeping and irq enable SH: shmobile: Consolidate time keeping and irq enable
arch/arm/include/asm/cpuidle.h | 22 +++++++++ arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/cpuidle.c | 21 ++++++++ arch/arm/mach-at91/cpuidle.c | 67 ++++++++++----------------- arch/arm/mach-davinci/cpuidle.c | 82 +++++++++++++------------------- arch/arm/mach-kirkwood/cpuidle.c | 72 ++++++++-------------------- arch/arm/mach-omap2/cpuidle34xx.c | 42 +++++++---------- arch/arm/mach-omap2/cpuidle44xx.c | 21 +------- arch/arm/mach-shmobile/cpuidle.c | 31 +++---------- arch/sh/kernel/cpu/shmobile/cpuidle.c | 10 +--- drivers/cpuidle/cpuidle.c | 79 +++++++++++++++++++++++++------ include/linux/cpuidle.h | 13 +++++- 12 files changed, 227 insertions(+), 235 deletions(-) create mode 100644 arch/arm/include/asm/cpuidle.h create mode 100644 arch/arm/kernel/cpuidle.c
The top-commit id is
bd7fd2ab3ee38df371ece6cd4997d6660b3e1c95
Acked-by: Jean Pihetj-pihet@ti.com (v6) Tested-by: Jean Pihetj-pihet@ti.com (v6, omap3) Tested-by: Amit Danielamit.kachhap@linaro.org (v6, Exynos4) Tested-by: Robert Leerob.lee@linaro.org (imx51, imx6q) Reviewed-by: Kevin Hilman khilman@ti.com Reviewed-by: Daniel Lezcano daniel.lezcano@linaro.org Reviewed-by: Deepthi Dharwardeepthi@linux.vnet.ibm.com (core cpuidle only)
These changes move various functionality duplicated in platform cpuidle drivers to the core cpuidle driver and common arch arm code. Also, the irq disabling in the platform code was removed as all calls into cpuidle_call_idle() will have already called local_irq_disable().
This patchset is bisect safe. Also, the core cpuidle and arch changes of the first commit do not require any changes to the arch and platform cpuidle drivers, though those arch and platform change should be made to take advantage of the new consolidation function.
Stephen, this patch has been reviewed, tested, and ACK'd per the list above but cpuidle maintainer Len Brown has been out on vacation for a couple of weeks so I am sending you this pull request as time is running out to get this into v3.4. I've had a brief communication with Andrew Morton about this as well so he is aware of this situation. I am fairly new to the community so please let me know if you see anything that needs my attention or anything I should be doing differently.
I've checked these changes against the recent linux-next tags and there is currently one small conflict due to a small change in arch/arm/mach-at91/cpuidle.c. I'd be happy to assist in resolving this issue if needed. Also, in my patchset submissions I include changes for a Samsung Exynos cpuidle platform driver patch that was accepted a couple of weeks ago but it hasn't yet made it to an rc so I am not including it in this request.
---------------------------
patchset submission history:
v7 submission can be found here: http://www.spinics.net/lists/arm-kernel/msg162290.html
v7 changes: * Made some struct whitespace alignment changes. * Fixed a coding style violation (thanks Jean Pihet) * Fixed a bug in davinci cpuidle (thanks Jean Pihet) * Corrected the common ARM cpuidle WFI state description to be ARM platform agnostic (thanks Kevin Hilman) * Fixed the problem causing x86 and PPC builds to fail (thanks Deepthi) * Re-added a line of code that was mistakenly removed (thanks Deepthi)
v6 submission can be found here: http://www.spinics.net/lists/arm-kernel/msg162018.html
v6 changes: * Fixed mindless bug in CONFIG_ARCH_HAS_RELAX code in drivers/cpuidle/cpuidle.c * Removed inline from wrapper function (thanks Mike Turquette and Rob Herring) * Add zeroing out of last_residency if error value is returned (thanks Mike) * Made drivers/cpuidle/cpuidle.c more intelligently handle en_core_tk_irqen flag allowing removal of the if (en_core_tk_irqen) in cpuidle_idle_call (thanks Daniel Lezcano) * Moved CPUIDLE_ARM_WFI_STATE macro to arch/arm/include/asm/cpuidle.h (thanks Jean Pihet) * Cleaned up some comments and a stray change (thanks Jean)
v5 submission can be found here: http://www.spinics.net/lists/arm-kernel/msg161596.html
v5 changes: * Added common cpu_do_idle function to core cpuidle * Added time keep irq en wrapper to core cpuidle * Removed pre/post enter * Re-added platforms that can use new common code.
v4 submission can be found here: http://lists.infradead.org/pipermail/linux-arm-kernel/2012-January/082742.ht...
v4 changes: * Removed drivers/cpuidle/common.c ** Removed the initialization helper functions ** Removed the wrapper used to consolidate time keeping and irq enable/disable * Add time keeping and local_irq_disable handling in cpuidle_call_idle(). * Made necessary modifications to a few platforms that required the most changes ** Note on omap3: changed structure of omap3_idle_drvdata and added per_next_state and per_saved_state vars to accomodate new framework.
v3 submission can be found here: http://www.spinics.net/lists/arm-kernel/msg156751.html
v3 changes: * Made various code organization and style changes as suggested in v2 review. (thanks Mark Brown, Rob Herring, Mike Turquette, Kevin Hillman, Daniel Lezcano) * Removed at91 use of common code. A separate effort is underway to clean at91 code and the author has offered to convert to common interface as part of those changes (if this common interface is accepted in time). * Made platform cpuidle_driver objects __initdata and dynamically added one persistent instance of this object in common code. * Removed imx5 pm usage of gpc_dvfs clock as it is no longer needed after being enabled during clock initialization. * Re-organized patches.
v2 submission can be found here: http://comments.gmane.org/gmane.linux.ports.arm.kernel/144199
v2 changes: * Common interface moved to drivers/cpuidle and made non arch-specific. * Made various fixes and suggested additions to the common cpuidle code from v1 review. (Thanks Rob Herring and Mark Brown) * Added callback for filling in driver_data field as needed. * Modified the various platforms with these changes.
v1 submission can be found here: http://comments.gmane.org/gmane.linux.ports.arm.kernel/142791
Thanks, Rob
Hi Rob,
On Thu, 8 Mar 2012 19:58:23 -0600 Rob Lee rob.lee@linaro.org wrote:
git://git.linaro.org/people/rob_lee/linux.git cpuidle_consol_pull
These changes move various functionality duplicated in platform cpuidle drivers to the core cpuidle driver and common arch arm code. Also, the irq disabling in the platform code was removed as all calls into cpuidle_call_idle() will have already called local_irq_disable().
This patchset is bisect safe. Also, the core cpuidle and arch changes of the first commit do not require any changes to the arch and platform cpuidle drivers, though those arch and platform change should be made to take advantage of the new consolidation function.
Stephen, this patch has been reviewed, tested, and ACK'd per the list above but cpuidle maintainer Len Brown has been out on vacation for a couple of weeks so I am sending you this pull request as time is running out to get this into v3.4. I've had a brief communication with Andrew Morton about this as well so he is aware of this situation. I am fairly new to the community so please let me know if you see anything that needs my attention or anything I should be doing differently.
I will add this tree from today. Lets see if anyone screams.
Thanks for adding your subsystem tree as a participant of linux-next. As you may know, this is not a judgment of your code. The purpose of linux-next is for integration testing and to lower the impact of conflicts between subsystems in the next merge window.
You will need to ensure that the patches/commits in your tree/series have been: * submitted under GPL v2 (or later) and include the Contributor's Signed-off-by, * posted to the relevant mailing list, * reviewed by you (or another maintainer of your subsystem tree), * successfully unit tested, and * destined for the current or next Linux merge window.
Basically, this should be just what you would send to Linus (or ask him to fetch). It is allowed to be rebased if you deem it necessary.
Good job Rob. Now you need to make sure that the branch you provided is up to date with Linus's latest -rc (aka rebase your branch every rc).
---------- Forwarded message ---------- From: Stephen Rothwell sfr@canb.auug.org.au Date: Fri, Mar 9, 2012 at 8:40 AM Subject: Re: [git pull] Consolidate cpuidle functionality To: Rob Lee rob.lee@linaro.org Cc: rjw@sisk.pl, len.brown@intel.com, nicolas.pitre@linaro.org, venki@google.com, linaro-dev@lists.linaro.org, linux-sh@vger.kernel.org, tony@atomide.com, nicolas.ferre@atmel.com, linux@arm.linux.org.uk, ccross@google.com, kernel@wantstofly.org, kgene.kim@samsung.com, mturquette@linaro.org, daniel.lezcano@linaro.org, magnus.damm@gmail.com, arnd.bergmann@linaro.org, jon-hunter@ti.com, patches@linaro.org, nsekhar@ti.com, jean.pihet@newoldbits.com, Baohua.Song@csr.com, vincent.guittot@linaro.org, linux-omap@vger.kernel.org, linux@maxim.org.za, linux-arm-kernel@lists.infradead.org, deepthi@linux.vnet.ibm.com, g.trinabh@gmail.com, linux-pm@vger.kernel.org, broonie@opensource.wolfsonmicro.com, amit.kucheria@linaro.org, lethal@linux-sh.org, amit.kachhap@linaro.org, Kevin Hilman khilman@ti.com, Andrew Morton akpm@linux-foundation.org
Hi Rob,
On Thu, 8 Mar 2012 19:58:23 -0600 Rob Lee rob.lee@linaro.org wrote:
git://git.linaro.org/people/rob_lee/linux.git cpuidle_consol_pull
These changes move various functionality duplicated in platform cpuidle drivers to the core cpuidle driver and common arch arm code. Also, the irq disabling in the platform code was removed as all calls into cpuidle_call_idle() will have already called local_irq_disable().
This patchset is bisect safe. Also, the core cpuidle and arch changes of the first commit do not require any changes to the arch and platform cpuidle drivers, though those arch and platform change should be made to take advantage of the new consolidation function.
Stephen, this patch has been reviewed, tested, and ACK'd per the list above but cpuidle maintainer Len Brown has been out on vacation for a couple of weeks so I am sending you this pull request as time is running out to get this into v3.4. I've had a brief communication with Andrew Morton about this as well so he is aware of this situation. I am fairly new to the community so please let me know if you see anything that needs my attention or anything I should be doing differently.
I will add this tree from today. Lets see if anyone screams.
Thanks for adding your subsystem tree as a participant of linux-next. As you may know, this is not a judgment of your code. The purpose of linux-next is for integration testing and to lower the impact of conflicts between subsystems in the next merge window.
You will need to ensure that the patches/commits in your tree/series have been: * submitted under GPL v2 (or later) and include the Contributor's Signed-off-by, * posted to the relevant mailing list, * reviewed by you (or another maintainer of your subsystem tree), * successfully unit tested, and * destined for the current or next Linux merge window.
Basically, this should be just what you would send to Linus (or ask him to fetch). It is allowed to be rebased if you deem it necessary.
-- Cheers, Stephen Rothwell sfr@canb.auug.org.au
Legal Stuff: By participating in linux-next, your subsystem tree contributions are public and will be included in the linux-next trees. You may be sent e-mail messages indicating errors or other issues when the patches/commits from your subsystem tree are merged and tested in linux-next. These messages may also be cross-posted to the linux-next mailing list, the linux-kernel mailing list, etc. The linux-next tree project and IBM (my employer) make no warranties regarding the linux-next project, the testing procedures, the results, the e-mails, etc. If you don't agree to these ground rules, let me know and I'll remove your tree from participation in linux-next.
Len and Andrew,
Please consider this an official merge request of this cpuidle patchset for v3.4.
There were two small conflicts Stephen Rothwell found when merging to linux-next. The first conflict is with patch 1/9 in the drivers/cpuidle/cpuidle.c file which is trivially to resolve. I'm told this fixup is trivially enough to not require anyone to carry it.
The second is with patch 2/9 in mach-at91/cpuidle.c due to some minor cleanup changes. The fix is also pretty simple but I'm waiting to hear back about who will carry it.
Please let me know if you need any other action or information on my part.
Thanks, Rob
On Fri, Mar 9, 2012 at 12:40 AM, Stephen Rothwell sfr@canb.auug.org.au wrote:
Hi Rob,
On Thu, 8 Mar 2012 19:58:23 -0600 Rob Lee rob.lee@linaro.org wrote:
git://git.linaro.org/people/rob_lee/linux.git cpuidle_consol_pull
These changes move various functionality duplicated in platform cpuidle drivers to the core cpuidle driver and common arch arm code. Also, the irq disabling in the platform code was removed as all calls into cpuidle_call_idle() will have already called local_irq_disable().
This patchset is bisect safe. Also, the core cpuidle and arch changes of the first commit do not require any changes to the arch and platform cpuidle drivers, though those arch and platform change should be made to take advantage of the new consolidation function.
Stephen, this patch has been reviewed, tested, and ACK'd per the list above but cpuidle maintainer Len Brown has been out on vacation for a couple of weeks so I am sending you this pull request as time is running out to get this into v3.4. I've had a brief communication with Andrew Morton about this as well so he is aware of this situation. I am fairly new to the community so please let me know if you see anything that needs my attention or anything I should be doing differently.
I will add this tree from today. Lets see if anyone screams.
Thanks for adding your subsystem tree as a participant of linux-next. As you may know, this is not a judgment of your code. The purpose of linux-next is for integration testing and to lower the impact of conflicts between subsystems in the next merge window.
You will need to ensure that the patches/commits in your tree/series have been: * submitted under GPL v2 (or later) and include the Contributor's Signed-off-by, * posted to the relevant mailing list, * reviewed by you (or another maintainer of your subsystem tree), * successfully unit tested, and * destined for the current or next Linux merge window.
Basically, this should be just what you would send to Linus (or ask him to fetch). It is allowed to be rebased if you deem it necessary.
-- Cheers, Stephen Rothwell sfr@canb.auug.org.au
Legal Stuff: By participating in linux-next, your subsystem tree contributions are public and will be included in the linux-next trees. You may be sent e-mail messages indicating errors or other issues when the patches/commits from your subsystem tree are merged and tested in linux-next. These messages may also be cross-posted to the linux-next mailing list, the linux-kernel mailing list, etc. The linux-next tree project and IBM (my employer) make no warranties regarding the linux-next project, the testing procedures, the results, the e-mails, etc. If you don't agree to these ground rules, let me know and I'll remove your tree from participation in linux-next.