From b60e6a0eb0273132cbb60a9806abf5f47a4aee1c Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Thu, 21 Mar 2013 12:21:31 +0000 Subject: cpuidle : handle clockevent notify from the cpuidle framework When a cpu enters a deep idle state, the local timers are stopped and the time framework falls back to the timer device used as a broadcast timer. The different cpuidle drivers are calling clockevents_notify ENTER/EXIT when the idle state stops the local timer. Add a new flag CPUIDLE_FLAG_TIMER_STOP which can be set by the cpuidle drivers. If the flag is set, the cpuidle core code takes care of the notification on behalf of the driver to avoid pointless code duplication. Signed-off-by: Daniel Lezcano Reviewed-by: Thomas Gleixner Acked-by: Santosh Shilimkar Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index eba6929..c500370 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -8,6 +8,7 @@ * This code is licenced under the GPL. */ +#include #include #include #include @@ -146,12 +147,20 @@ int cpuidle_idle_call(void) trace_cpu_idle_rcuidle(next_state, dev->cpu); + if (drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP) + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, + &dev->cpu); + if (cpuidle_state_is_coupled(dev, drv, next_state)) entered_state = cpuidle_enter_state_coupled(dev, drv, next_state); else entered_state = cpuidle_enter_state(dev, drv, next_state); + if (drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP) + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, + &dev->cpu); + trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); /* give the governor an opportunity to reflect on the outcome */ diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 480c14d..a837b33 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -57,6 +57,7 @@ struct cpuidle_state { /* Idle State Flags */ #define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */ #define CPUIDLE_FLAG_COUPLED (0x02) /* state applies to multiple cpus */ +#define CPUIDLE_FLAG_TIMER_STOP (0x04) /* timer is stopped on this state */ #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000) -- cgit v0.10.2 From cb7094e848f7bcaa0a4cda3db4b232f08dbf5b78 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Thu, 21 Mar 2013 12:21:32 +0000 Subject: cpuidle / omap4 : use CPUIDLE_FLAG_TIMER_STOP flag Use the CPUIDLE_FLAG_TIMER_STOP and let the cpuidle framework to handle the CLOCK_EVT_NOTIFY_BROADCAST_ENTER/EXIT when entering this state. Signed-off-by: Daniel Lezcano Acked-by: Santosh Shilimkar Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index d639aef..fe0e025 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -82,7 +82,6 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev, int index) { struct omap4_idle_statedata *cx = &omap4_idle_data[index]; - int cpu_id = smp_processor_id(); local_fiq_disable(); @@ -109,8 +108,6 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev, } } - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu_id); - /* * Call idle CPU PM enter notifier chain so that * VFP and per CPU interrupt context is saved. @@ -152,8 +149,6 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev, if (omap4_mpuss_read_prev_context_state()) cpu_cluster_pm_exit(); - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu_id); - fail: cpuidle_coupled_parallel_barrier(dev, &abort_barrier); cpu_done[dev->cpu] = false; @@ -193,7 +188,8 @@ static struct cpuidle_driver omap4_idle_driver = { /* C2 - CPU0 OFF + CPU1 OFF + MPU CSWR */ .exit_latency = 328 + 440, .target_residency = 960, - .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED, + .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED | + CPUIDLE_FLAG_TIMER_STOP, .enter = omap4_enter_idle_coupled, .name = "C2", .desc = "MPUSS CSWR", @@ -202,7 +198,8 @@ static struct cpuidle_driver omap4_idle_driver = { /* C3 - CPU0 OFF + CPU1 OFF + MPU OSWR */ .exit_latency = 460 + 518, .target_residency = 1100, - .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED, + .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED | + CPUIDLE_FLAG_TIMER_STOP, .enter = omap4_enter_idle_coupled, .name = "C3", .desc = "MPUSS OSWR", -- cgit v0.10.2 From 8de46eff656f028b120971ba0edabaab09d854f2 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Thu, 21 Mar 2013 12:21:33 +0000 Subject: cpuidle / imx6 : use CPUIDLE_FLAG_TIMER_STOP flag Use the CPUIDLE_FLAG_TIMER_STOP and let the cpuidle framework to handle the CLOCK_EVT_NOTIFY_BROADCAST_ENTER/EXIT when entering this state. Signed-off-by: Daniel Lezcano Acked-by: Santosh Shilimkar Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c index d533e26..5ae22f7 100644 --- a/arch/arm/mach-imx/cpuidle-imx6q.c +++ b/arch/arm/mach-imx/cpuidle-imx6q.c @@ -21,10 +21,6 @@ static DEFINE_SPINLOCK(master_lock); static int imx6q_enter_wait(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { - int cpu = dev->cpu; - - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); - if (atomic_inc_return(&master) == num_online_cpus()) { /* * With this lock, we prevent other cpu to exit and enter @@ -43,7 +39,6 @@ idle: cpu_do_idle(); done: atomic_dec(&master); - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); return index; } @@ -70,7 +65,8 @@ static struct cpuidle_driver imx6q_cpuidle_driver = { { .exit_latency = 50, .target_residency = 75, - .flags = CPUIDLE_FLAG_TIME_VALID, + .flags = CPUIDLE_FLAG_TIME_VALID | + CPUIDLE_FLAG_TIMER_STOP, .enter = imx6q_enter_wait, .name = "WAIT", .desc = "Clock off", -- cgit v0.10.2 From d2b578e5fc189d6948eb48bdaf2156f74aecf69c Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Thu, 21 Mar 2013 12:21:34 +0000 Subject: cpuidle / ux500 : use CPUIDLE_FLAG_TIMER_STOP flag Use the CPUIDLE_FLAG_TIMER_STOP and let the cpuidle framework to handle the CLOCK_EVT_NOTIFY_BROADCAST_ENTER/EXIT when entering this state. Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-ux500/cpuidle.c b/arch/arm/mach-ux500/cpuidle.c index ce91493..6d0c4b6 100644 --- a/arch/arm/mach-ux500/cpuidle.c +++ b/arch/arm/mach-ux500/cpuidle.c @@ -30,8 +30,6 @@ static inline int ux500_enter_idle(struct cpuidle_device *dev, int this_cpu = smp_processor_id(); bool recouple = false; - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &this_cpu); - if (atomic_inc_return(&master) == num_online_cpus()) { /* With this lock, we prevent the other cpu to exit and enter @@ -91,8 +89,6 @@ out: spin_unlock(&master_lock); } - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &this_cpu); - return index; } @@ -106,7 +102,8 @@ static struct cpuidle_driver ux500_idle_driver = { .enter = ux500_enter_idle, .exit_latency = 70, .target_residency = 260, - .flags = CPUIDLE_FLAG_TIME_VALID, + .flags = CPUIDLE_FLAG_TIME_VALID | + CPUIDLE_FLAG_TIMER_STOP, .name = "ApIdle", .desc = "ARM Retention", }, -- cgit v0.10.2 From 9a23fe65cf36efc6cb40e96405a3f142c7732805 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 12 Mar 2013 09:27:55 +0000 Subject: cpuidle / kirkwood: remove redundant Kconfig option When the CPU_IDLE and the ARCH_KIRKWOOD options are set it is pointless to define a new option CPU_IDLE_KIRKWOOD because it is redundant. The Makefile drivers directory contains a condition to compile the cpuidle drivers: obj-$(CONFIG_CPU_IDLE) += cpuidle/ Hence, if CPU_IDLE is not set we won't enter this directory. This patch removes the useless Kconfig option and replaces the condition in the Makefile by CONFIG_ARCH_KIRKWOOD. Signed-off-by: Daniel Lezcano Acked-by: Jason Cooper Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/configs/kirkwood_defconfig b/arch/arm/configs/kirkwood_defconfig index 13482ea..93f3794 100644 --- a/arch/arm/configs/kirkwood_defconfig +++ b/arch/arm/configs/kirkwood_defconfig @@ -56,7 +56,6 @@ CONFIG_AEABI=y CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_CPU_IDLE=y -CONFIG_CPU_IDLE_KIRKWOOD=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index 071e2c3..c4cc27e 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig @@ -39,10 +39,4 @@ config CPU_IDLE_CALXEDA help Select this to enable cpuidle on Calxeda processors. -config CPU_IDLE_KIRKWOOD - bool "CPU Idle Driver for Kirkwood processors" - depends on ARCH_KIRKWOOD - help - Select this to enable cpuidle on Kirkwood processors. - endif diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile index 24c6e7d..0d8bd55 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile @@ -6,4 +6,4 @@ obj-y += cpuidle.o driver.o governor.o sysfs.o governors/ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o -obj-$(CONFIG_CPU_IDLE_KIRKWOOD) += cpuidle-kirkwood.o +obj-$(CONFIG_ARCH_KIRKWOOD) += cpuidle-kirkwood.o -- cgit v0.10.2 From 488540bf41ce8ccfe8b54c646c3ea67a7196edcd Mon Sep 17 00:00:00 2001 From: Silviu-Mihai Popescu Date: Fri, 22 Mar 2013 14:10:42 +0100 Subject: cpuidle: kirkwood: fix coccicheck warnings Convert all uses of devm_request_and_ioremap() to the newly introduced devm_ioremap_resource() which provides more consistent error handling. devm_ioremap_resource() provides its own error messages so all explicit error messages can be removed from the failure code paths. Signed-off-by: Silviu-Mihai Popescu Reviewed-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/cpuidle-kirkwood.c b/drivers/cpuidle/cpuidle-kirkwood.c index 670aa1e..53aad73 100644 --- a/drivers/cpuidle/cpuidle-kirkwood.c +++ b/drivers/cpuidle/cpuidle-kirkwood.c @@ -66,9 +66,9 @@ static int kirkwood_cpuidle_probe(struct platform_device *pdev) if (res == NULL) return -EINVAL; - ddr_operation_base = devm_request_and_ioremap(&pdev->dev, res); - if (!ddr_operation_base) - return -EADDRNOTAVAIL; + ddr_operation_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ddr_operation_base)) + return PTR_ERR(ddr_operation_base); device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id()); device->state_count = KIRKWOOD_MAX_STATES; -- cgit v0.10.2 From 4dbad816febb6cb7340e36af4f5c0dc86e55a2ca Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 27 Mar 2013 10:22:09 +0000 Subject: timer: move enum definition out of ifdef section The next patch will setup automatically the broadcast timer for the different cpuidle driver when one idle state stops its timer. This will be part of the generic code. But some ARM boards, like s3c64xx, uses cpuidle but without the CONFIG_GENERIC_CLOCKEVENTS_BUILD set. Hence the cpuidle framework will be compiled with the code supposed to be generic, that is with clockevents_notify and the different enum. Also the function clockevents_notify is a noop macro, this is fine except the usual code is: int cpu = smp_processor_id(); clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu); and that raises a warning for the variable cpu which is not used. Move the clock_event_nofitiers enum definition out of the CONFIG_GENERIC_CLOCKEVENTS_BUILD section to prevent a compilation error when these are used in the code. Change the clockevents_notify macro to a static inline noop function to prevent a compilation warning. Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index 6634652..f9fd937 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h @@ -8,6 +8,20 @@ #ifndef _LINUX_CLOCKCHIPS_H #define _LINUX_CLOCKCHIPS_H +/* Clock event notification values */ +enum clock_event_nofitiers { + CLOCK_EVT_NOTIFY_ADD, + CLOCK_EVT_NOTIFY_BROADCAST_ON, + CLOCK_EVT_NOTIFY_BROADCAST_OFF, + CLOCK_EVT_NOTIFY_BROADCAST_FORCE, + CLOCK_EVT_NOTIFY_BROADCAST_ENTER, + CLOCK_EVT_NOTIFY_BROADCAST_EXIT, + CLOCK_EVT_NOTIFY_SUSPEND, + CLOCK_EVT_NOTIFY_RESUME, + CLOCK_EVT_NOTIFY_CPU_DYING, + CLOCK_EVT_NOTIFY_CPU_DEAD, +}; + #ifdef CONFIG_GENERIC_CLOCKEVENTS_BUILD #include @@ -26,20 +40,6 @@ enum clock_event_mode { CLOCK_EVT_MODE_RESUME, }; -/* Clock event notification values */ -enum clock_event_nofitiers { - CLOCK_EVT_NOTIFY_ADD, - CLOCK_EVT_NOTIFY_BROADCAST_ON, - CLOCK_EVT_NOTIFY_BROADCAST_OFF, - CLOCK_EVT_NOTIFY_BROADCAST_FORCE, - CLOCK_EVT_NOTIFY_BROADCAST_ENTER, - CLOCK_EVT_NOTIFY_BROADCAST_EXIT, - CLOCK_EVT_NOTIFY_SUSPEND, - CLOCK_EVT_NOTIFY_RESUME, - CLOCK_EVT_NOTIFY_CPU_DYING, - CLOCK_EVT_NOTIFY_CPU_DEAD, -}; - /* * Clock event features */ @@ -173,7 +173,7 @@ extern int tick_receive_broadcast(void); #ifdef CONFIG_GENERIC_CLOCKEVENTS extern void clockevents_notify(unsigned long reason, void *arg); #else -# define clockevents_notify(reason, arg) do { } while (0) +static inline void clockevents_notify(unsigned long reason, void *arg) {} #endif #else /* CONFIG_GENERIC_CLOCKEVENTS_BUILD */ @@ -181,7 +181,7 @@ extern void clockevents_notify(unsigned long reason, void *arg); static inline void clockevents_suspend(void) {} static inline void clockevents_resume(void) {} -#define clockevents_notify(reason, arg) do { } while (0) +static inline void clockevents_notify(unsigned long reason, void *arg) {} #endif -- cgit v0.10.2 From a06df062a189a8d5588babb8bf0bb78672497798 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 27 Mar 2013 10:22:10 +0000 Subject: cpuidle: initialize the broadcast timer framework The commit 89878baa73f0f1c679355006bd8632e5d78f96c2 introduced the CPUIDLE_FLAG_TIMER_STOP flag where we specify a specific idle state stops the local timer. Now use this flag to check at init time if one state will need the broadcast timer and, in this case, setup the broadcast timer framework. That prevents multiple code duplication in the drivers. Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index 422c7b6..8dfaaae 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include "cpuidle.h" @@ -19,9 +21,28 @@ DEFINE_SPINLOCK(cpuidle_driver_lock); static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu); static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu); -static void __cpuidle_driver_init(struct cpuidle_driver *drv) +static void cpuidle_setup_broadcast_timer(void *arg) { + int cpu = smp_processor_id(); + clockevents_notify((long)(arg), &cpu); +} + +static void __cpuidle_driver_init(struct cpuidle_driver *drv, int cpu) +{ + int i; + drv->refcnt = 0; + + for (i = drv->state_count - 1; i >= 0 ; i--) { + + if (!(drv->states[i].flags & CPUIDLE_FLAG_TIMER_STOP)) + continue; + + drv->bctimer = 1; + on_each_cpu_mask(get_cpu_mask(cpu), cpuidle_setup_broadcast_timer, + (void *)CLOCK_EVT_NOTIFY_BROADCAST_ON, 1); + break; + } } static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu) @@ -35,7 +56,7 @@ static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu) if (__cpuidle_get_cpu_driver(cpu)) return -EBUSY; - __cpuidle_driver_init(drv); + __cpuidle_driver_init(drv, cpu); __cpuidle_set_cpu_driver(drv, cpu); @@ -49,6 +70,12 @@ static void __cpuidle_unregister_driver(struct cpuidle_driver *drv, int cpu) if (!WARN_ON(drv->refcnt > 0)) __cpuidle_set_cpu_driver(NULL, cpu); + + if (drv->bctimer) { + drv->bctimer = 0; + on_each_cpu_mask(get_cpu_mask(cpu), cpuidle_setup_broadcast_timer, + (void *)CLOCK_EVT_NOTIFY_BROADCAST_OFF, 1); + } } #ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index a837b33..fc3e580 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -107,6 +107,8 @@ struct cpuidle_driver { /* set to 1 to use the core cpuidle time keeping (for all states). */ unsigned int en_core_tk_irqen:1; + /* used by the cpuidle framework to setup the broadcast timer */ + unsigned int bctimer:1; /* states array must be ordered in decreasing power consumption */ struct cpuidle_state states[CPUIDLE_STATE_MAX]; int state_count; -- cgit v0.10.2 From a454afa5c371d862385db2bf3154d9ed9038246b Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 27 Mar 2013 10:22:11 +0000 Subject: cpuidle: ux500: remove timer broadcast initialization The initialization is done from the cpuidle framework. Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-ux500/cpuidle.c b/arch/arm/mach-ux500/cpuidle.c index 6d0c4b6..1b16d9e 100644 --- a/arch/arm/mach-ux500/cpuidle.c +++ b/arch/arm/mach-ux500/cpuidle.c @@ -11,7 +11,6 @@ #include #include -#include #include #include #include @@ -112,16 +111,6 @@ static struct cpuidle_driver ux500_idle_driver = { .state_count = 2, }; -/* - * For each cpu, setup the broadcast timer because we will - * need to migrate the timers for the states >= ApIdle. - */ -static void ux500_setup_broadcast_timer(void *arg) -{ - int cpu = smp_processor_id(); - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu); -} - int __init ux500_idle_init(void) { int ret, cpu; @@ -131,13 +120,6 @@ int __init ux500_idle_init(void) prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) | PRCMU_WAKEUP(ABB)); - /* - * Configure the timer broadcast for each cpu, that must - * be done from the cpu context, so we use a smp cross - * call with 'on_each_cpu'. - */ - on_each_cpu(ux500_setup_broadcast_timer, NULL, 1); - ret = cpuidle_register_driver(&ux500_idle_driver); if (ret) { printk(KERN_ERR "failed to register ux500 idle driver\n"); -- cgit v0.10.2 From 54769d653a8cf5e0fe7e78b92d7b4c4c65722b36 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 27 Mar 2013 10:22:12 +0000 Subject: cpuidle: OMAP4: remove timer broadcast initialization The initialization is done from the cpuidle framework. Signed-off-by: Daniel Lezcano Acked-by: Santosh Shilimkar Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index fe0e025..f4b1b23 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -14,7 +14,6 @@ #include #include #include -#include #include @@ -158,16 +157,6 @@ fail: return index; } -/* - * For each cpu, setup the broadcast timer because local timers - * stops for the states above C1. - */ -static void omap_setup_broadcast_timer(void *arg) -{ - int cpu = smp_processor_id(); - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu); -} - static DEFINE_PER_CPU(struct cpuidle_device, omap4_idle_dev); static struct cpuidle_driver omap4_idle_driver = { @@ -233,9 +222,6 @@ int __init omap4_idle_init(void) if (!cpu_clkdm[0] || !cpu_clkdm[1]) return -ENODEV; - /* Configure the broadcast timer on each cpu */ - on_each_cpu(omap_setup_broadcast_timer, NULL, 1); - for_each_cpu(cpu_id, cpu_online_mask) { dev = &per_cpu(omap4_idle_dev, cpu_id); dev->cpu = cpu_id; -- cgit v0.10.2 From b6269efb146eb8770d753e3dc1c561f1cffb631a Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 27 Mar 2013 10:22:13 +0000 Subject: cpuidle: imx6: remove timer broadcast initialization The initialization is done from the cpuidle framework. Signed-off-by: Daniel Lezcano Acked-by: Shawn Guo Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c index 5ae22f7..a783a63 100644 --- a/arch/arm/mach-imx/cpuidle-imx6q.c +++ b/arch/arm/mach-imx/cpuidle-imx6q.c @@ -6,7 +6,6 @@ * published by the Free Software Foundation. */ -#include #include #include #include @@ -43,17 +42,6 @@ done: return index; } -/* - * For each cpu, setup the broadcast timer because local timer - * stops for the states other than WFI. - */ -static void imx6q_setup_broadcast_timer(void *arg) -{ - int cpu = smp_processor_id(); - - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu); -} - static struct cpuidle_driver imx6q_cpuidle_driver = { .name = "imx6q_cpuidle", .owner = THIS_MODULE, @@ -84,8 +72,5 @@ int __init imx6q_cpuidle_init(void) /* Set chicken bit to get a reliable WAIT mode support */ imx6q_set_chicken_bit(); - /* Configure the broadcast timer on each cpu */ - on_each_cpu(imx6q_setup_broadcast_timer, NULL, 1); - return imx_cpuidle_init(&imx6q_cpuidle_driver); } -- cgit v0.10.2 From d50470979090bb5fa6c198d0ef87276658deb5f9 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 3 Apr 2013 12:15:15 +0000 Subject: ARM: shmobile: pm: fix init sections Add the __init section for the functions which are called at init time. Signed-off-by: Daniel Lezcano Acked-by: Simon Horman Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-shmobile/cpuidle.c b/arch/arm/mach-shmobile/cpuidle.c index 9e05026..068f9ca 100644 --- a/arch/arm/mach-shmobile/cpuidle.c +++ b/arch/arm/mach-shmobile/cpuidle.c @@ -36,12 +36,12 @@ static struct cpuidle_driver shmobile_cpuidle_default_driver = { static struct cpuidle_driver *cpuidle_drv = &shmobile_cpuidle_default_driver; -void shmobile_cpuidle_set_driver(struct cpuidle_driver *drv) +void __init shmobile_cpuidle_set_driver(struct cpuidle_driver *drv) { cpuidle_drv = drv; } -int shmobile_cpuidle_init(void) +int __init shmobile_cpuidle_init(void) { struct cpuidle_device *dev = &shmobile_cpuidle_dev; diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c index a0826a4..f6b14ca 100644 --- a/arch/arm/mach-shmobile/pm-sh7372.c +++ b/arch/arm/mach-shmobile/pm-sh7372.c @@ -450,12 +450,12 @@ static struct cpuidle_driver sh7372_cpuidle_driver = { }, }; -static void sh7372_cpuidle_init(void) +static void __init sh7372_cpuidle_init(void) { shmobile_cpuidle_set_driver(&sh7372_cpuidle_driver); } #else -static void sh7372_cpuidle_init(void) {} +static void __init sh7372_cpuidle_init(void) {} #endif #ifdef CONFIG_SUSPEND -- cgit v0.10.2 From 688036b538974de32ce55be8b0e013b003992abc Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 3 Apr 2013 12:15:16 +0000 Subject: ARM: shmobile: cpuidle: remove useless WFI function Remove the shmobile_enter_wfi function which is the same as the common WFI enter function from the arm cpuidle driver defined with the ARM_CPUIDLE_WFI_STATE macro. Signed-off-by: Daniel Lezcano Acked-by: Simon Horman Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-shmobile/cpuidle.c b/arch/arm/mach-shmobile/cpuidle.c index 068f9ca..c872ae8 100644 --- a/arch/arm/mach-shmobile/cpuidle.c +++ b/arch/arm/mach-shmobile/cpuidle.c @@ -16,20 +16,12 @@ #include #include -int shmobile_enter_wfi(struct cpuidle_device *dev, struct cpuidle_driver *drv, - int index) -{ - cpu_do_idle(); - return 0; -} - static struct cpuidle_device shmobile_cpuidle_dev; static struct cpuidle_driver shmobile_cpuidle_default_driver = { .name = "shmobile_cpuidle", .owner = THIS_MODULE, .en_core_tk_irqen = 1, .states[0] = ARM_CPUIDLE_WFI_STATE, - .states[0].enter = shmobile_enter_wfi, .safe_state_index = 0, /* C1 */ .state_count = 1, }; -- cgit v0.10.2 From 14ad7a119b85b0ba77868882194ab5b16203b2c9 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 3 Apr 2013 12:15:17 +0000 Subject: ARM: tegra2: cpuidle: change driver initialization Initialize the idle states directly in the driver structure. That prevents extra structure declaration and memcpy at init time. Signed-off-by: Daniel Lezcano Reviewed-by: Joseph Lo Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c index 825ced4..1ad1a67 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra20.c +++ b/arch/arm/mach-tegra/cpuidle-tegra20.c @@ -43,28 +43,32 @@ static atomic_t abort_barrier; static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index); +#define TEGRA20_MAX_STATES 2 +#else +#define TEGRA20_MAX_STATES 1 #endif -static struct cpuidle_state tegra_idle_states[] = { - [0] = ARM_CPUIDLE_WFI_STATE_PWR(600), -#ifdef CONFIG_PM_SLEEP - [1] = { - .enter = tegra20_idle_lp2_coupled, - .exit_latency = 5000, - .target_residency = 10000, - .power_usage = 0, - .flags = CPUIDLE_FLAG_TIME_VALID | - CPUIDLE_FLAG_COUPLED, - .name = "powered-down", - .desc = "CPU power gated", - }, -#endif -}; - static struct cpuidle_driver tegra_idle_driver = { .name = "tegra_idle", .owner = THIS_MODULE, .en_core_tk_irqen = 1, + .states = { + ARM_CPUIDLE_WFI_STATE_PWR(600), +#ifdef CONFIG_PM_SLEEP + { + .enter = tegra20_idle_lp2_coupled, + .exit_latency = 5000, + .target_residency = 10000, + .power_usage = 0, + .flags = CPUIDLE_FLAG_TIME_VALID | + CPUIDLE_FLAG_COUPLED, + .name = "powered-down", + .desc = "CPU power gated", + }, +#endif + }, + .state_count = TEGRA20_MAX_STATES, + .safe_state_index = 0, }; static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device); @@ -226,10 +230,6 @@ int __init tegra20_cpuidle_init(void) tegra_tear_down_cpu = tegra20_tear_down_cpu; #endif - drv->state_count = ARRAY_SIZE(tegra_idle_states); - memcpy(drv->states, tegra_idle_states, - drv->state_count * sizeof(drv->states[0])); - ret = cpuidle_register_driver(&tegra_idle_driver); if (ret) { pr_err("CPUidle driver registration failed\n"); -- cgit v0.10.2 From 0697598db56179dbaa9376f29703f6b94751a73f Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 3 Apr 2013 12:15:18 +0000 Subject: ARM: tegra: cpuidle: remove useless initialization dev->state_count is initialized automatically by cpuidle_register_device(). When drv->state_count is equal to dev->state_count, no need to init this field, so removing it. Signed-off-by: Daniel Lezcano Reviewed-by: Joseph Lo Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c index 0f4e8c4..c527cff 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra114.c +++ b/arch/arm/mach-tegra/cpuidle-tegra114.c @@ -49,7 +49,6 @@ int __init tegra114_cpuidle_init(void) dev = &per_cpu(tegra_idle_device, cpu); dev->cpu = cpu; - dev->state_count = drv->state_count; ret = cpuidle_register_device(dev); if (ret) { pr_err("CPU%u: CPUidle device registration failed\n", diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c index 1ad1a67..b94d76a 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra20.c +++ b/arch/arm/mach-tegra/cpuidle-tegra20.c @@ -243,7 +243,6 @@ int __init tegra20_cpuidle_init(void) dev->coupled_cpus = *cpu_possible_mask; #endif - dev->state_count = drv->state_count; ret = cpuidle_register_device(dev); if (ret) { pr_err("CPU%u: CPUidle device registration failed\n", diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c index 8b50cf4..c4e01fe 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra30.c +++ b/arch/arm/mach-tegra/cpuidle-tegra30.c @@ -176,7 +176,6 @@ int __init tegra30_cpuidle_init(void) dev = &per_cpu(tegra_idle_device, cpu); dev->cpu = cpu; - dev->state_count = drv->state_count; ret = cpuidle_register_device(dev); if (ret) { pr_err("CPU%u: CPUidle device registration failed\n", -- cgit v0.10.2 From c062d44311107de7e384e26d7b97803657cf44f8 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 3 Apr 2013 12:15:19 +0000 Subject: ARM: davinci: cpuidle: fix wrong enter function The davinci_enter_idle is called from the cpuidle with the cpuidle_wrap_enter function. This one does the time compution for entering and exiting the idle function and then we call again cpuidle_wrap_enter for cpu_do_idle. This is wrong, we are calling recursively cpuidle_wrap_enter for nothing and furthermore reenabling the local irq. Remove this and replace it by the cpu_do_idle function. Signed-off-by: Daniel Lezcano Acked-by: Santosh Shilimkar Acked-by: Sekhar Nori Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c index 5ac9e93..22d6d4a 100644 --- a/arch/arm/mach-davinci/cpuidle.c +++ b/arch/arm/mach-davinci/cpuidle.c @@ -50,14 +50,10 @@ static void davinci_save_ddr_power(int enter, bool pdown) /* 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_driver *drv, int index) { davinci_save_ddr_power(1, ddr2_pdown); - - index = cpuidle_wrap_enter(dev, drv, index, - arm_cpuidle_simple_enter); - + cpu_do_idle(); davinci_save_ddr_power(0, ddr2_pdown); return index; -- cgit v0.10.2 From 561a07ac1c595572cbdbf459de87b319cba638ca Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 3 Apr 2013 12:15:21 +0000 Subject: ARM: omap3: cpuidle: enable time keeping The TIME_VALID flag is specified for the different states but the time residency computation is not done, no tk flag, no time computation in the idle function. Set the en_core_tk_irqen flag to activate it. Signed-off-by: Daniel Lezcano Acked-by: Santosh Shilimkar Acked-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 80392fc..4f67a5b 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -274,8 +274,9 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, static DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev); static struct cpuidle_driver omap3_idle_driver = { - .name = "omap3_idle", - .owner = THIS_MODULE, + .name = "omap3_idle", + .owner = THIS_MODULE, + .en_core_tk_irqen = 1, .states = { { .enter = omap3_enter_idle_bm, -- cgit v0.10.2 From 1ca8094403ae5553c6a0f404842be3075b302c70 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 3 Apr 2013 12:15:22 +0000 Subject: POWERPC: pseries: cpuidle: use time keeping flag The current code computes the idle time but that can be handled by the cpuidle framework if we enable the .en_core_tk_irqen flag. Set the flag and remove the code related to the time computation. Signed-off-by: Daniel Lezcano Signed-off-by: Deepthi Dharwar Signed-off-by: Rafael J. Wysocki diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c index 4d806b4..a197120 100644 --- a/arch/powerpc/platforms/pseries/processor_idle.c +++ b/arch/powerpc/platforms/pseries/processor_idle.c @@ -23,8 +23,9 @@ #include "pseries.h" struct cpuidle_driver pseries_idle_driver = { - .name = "pseries_idle", - .owner = THIS_MODULE, + .name = "pseries_idle", + .owner = THIS_MODULE, + .en_core_tk_irqen = 1, }; #define MAX_IDLE_STATE_COUNT 2 @@ -33,10 +34,8 @@ static int max_idle_state = MAX_IDLE_STATE_COUNT - 1; static struct cpuidle_device __percpu *pseries_cpuidle_devices; static struct cpuidle_state *cpuidle_state_table; -static inline void idle_loop_prolog(unsigned long *in_purr, ktime_t *kt_before) +static inline void idle_loop_prolog(unsigned long *in_purr) { - - *kt_before = ktime_get(); *in_purr = mfspr(SPRN_PURR); /* * Indicate to the HV that we are idle. Now would be @@ -45,12 +44,10 @@ static inline void idle_loop_prolog(unsigned long *in_purr, ktime_t *kt_before) get_lppaca()->idle = 1; } -static inline s64 idle_loop_epilog(unsigned long in_purr, ktime_t kt_before) +static inline void idle_loop_epilog(unsigned long in_purr) { get_lppaca()->wait_state_cycles += mfspr(SPRN_PURR) - in_purr; get_lppaca()->idle = 0; - - return ktime_to_us(ktime_sub(ktime_get(), kt_before)); } static int snooze_loop(struct cpuidle_device *dev, @@ -58,10 +55,9 @@ static int snooze_loop(struct cpuidle_device *dev, int index) { unsigned long in_purr; - ktime_t kt_before; int cpu = dev->cpu; - idle_loop_prolog(&in_purr, &kt_before); + idle_loop_prolog(&in_purr); local_irq_enable(); set_thread_flag(TIF_POLLING_NRFLAG); @@ -75,8 +71,8 @@ static int snooze_loop(struct cpuidle_device *dev, clear_thread_flag(TIF_POLLING_NRFLAG); smp_mb(); - dev->last_residency = - (int)idle_loop_epilog(in_purr, kt_before); + idle_loop_epilog(in_purr); + return index; } @@ -102,9 +98,8 @@ static int dedicated_cede_loop(struct cpuidle_device *dev, int index) { unsigned long in_purr; - ktime_t kt_before; - idle_loop_prolog(&in_purr, &kt_before); + idle_loop_prolog(&in_purr); get_lppaca()->donate_dedicated_cpu = 1; ppc64_runlatch_off(); @@ -112,8 +107,9 @@ static int dedicated_cede_loop(struct cpuidle_device *dev, check_and_cede_processor(); get_lppaca()->donate_dedicated_cpu = 0; - dev->last_residency = - (int)idle_loop_epilog(in_purr, kt_before); + + idle_loop_epilog(in_purr); + return index; } @@ -122,9 +118,8 @@ static int shared_cede_loop(struct cpuidle_device *dev, int index) { unsigned long in_purr; - ktime_t kt_before; - idle_loop_prolog(&in_purr, &kt_before); + idle_loop_prolog(&in_purr); /* * Yield the processor to the hypervisor. We return if @@ -135,8 +130,8 @@ static int shared_cede_loop(struct cpuidle_device *dev, */ check_and_cede_processor(); - dev->last_residency = - (int)idle_loop_epilog(in_purr, kt_before); + idle_loop_epilog(in_purr); + return index; } -- cgit v0.10.2 From 0d97558901c446a989de202a5d9ae94ec53644e5 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 29 Mar 2013 11:31:35 +0100 Subject: ARM: omap3: cpuidle: enable time keeping The TIME_VALID flag is specified for the different states but the time residency computation is not done, no tk flag, no time computation in the idle function. Set the en_core_tk_irqen flag to activate it. Cc: stable@vger.kernel.org Signed-off-by: Daniel Lezcano Acked-by: Santosh Shilimkar Signed-off-by: Kevin Hilman diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 80392fc..4f67a5b 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -274,8 +274,9 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, static DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev); static struct cpuidle_driver omap3_idle_driver = { - .name = "omap3_idle", - .owner = THIS_MODULE, + .name = "omap3_idle", + .owner = THIS_MODULE, + .en_core_tk_irqen = 1, .states = { { .enter = omap3_enter_idle_bm, -- cgit v0.10.2 From dbd1ba6a62408520e5c7a024b521af14e71b2987 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Mon, 25 Mar 2013 15:35:04 +0530 Subject: ARM: OMAP4: CPUidle: Avoid double idle driver registration OMAP4 CPUidle driver registration call is under a loop which leads to calling cpuidle_register_driver twice which is not intended. Fix it by moving the driver registration outside the loop. Reported-by: Nishanth Menon Acked-by: Nishanth Menon Signed-off-by: Santosh Shilimkar Signed-off-by: Kevin Hilman diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index f4b1b23..72c5407 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -222,14 +222,14 @@ int __init omap4_idle_init(void) if (!cpu_clkdm[0] || !cpu_clkdm[1]) return -ENODEV; + cpuidle_register_driver(&omap4_idle_driver); + for_each_cpu(cpu_id, cpu_online_mask) { dev = &per_cpu(omap4_idle_dev, cpu_id); dev->cpu = cpu_id; #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED dev->coupled_cpus = *cpu_online_mask; #endif - cpuidle_register_driver(&omap4_idle_driver); - if (cpuidle_register_device(dev)) { pr_err("%s: CPUidle register failed\n", __func__); return -EIO; -- cgit v0.10.2 From 63b951ed5b82c2891982437d1f57cb94dc0b3757 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Mon, 25 Mar 2013 15:35:05 +0530 Subject: ARM: OMAP: CPUidle: Unregister drivere on device registration failure If the CPUidle device registration fails for some reason, we should unregister the driver on error path. Fix the code accordingly. Also when at it, check of the driver registration failure too. Acked-by: Nishanth Menon Signed-off-by: Santosh Shilimkar Signed-off-by: Kevin Hilman diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 4f67a5b..a300122 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -359,7 +359,10 @@ int __init omap3_idle_init(void) if (!mpu_pd || !core_pd || !per_pd || !cam_pd) return -ENODEV; - cpuidle_register_driver(&omap3_idle_driver); + if (cpuidle_register_driver(&omap3_idle_driver)) { + pr_err("%s: CPUidle driver register failed\n", __func__); + return -EIO; + } dev = &per_cpu(omap3_idle_dev, smp_processor_id()); dev->cpu = 0; @@ -367,6 +370,7 @@ int __init omap3_idle_init(void) if (cpuidle_register_device(dev)) { printk(KERN_ERR "%s: CPUidle register device failed\n", __func__); + cpuidle_unregister_driver(&omap3_idle_driver); return -EIO; } diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index 72c5407..aeeb8e6 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -222,7 +222,10 @@ int __init omap4_idle_init(void) if (!cpu_clkdm[0] || !cpu_clkdm[1]) return -ENODEV; - cpuidle_register_driver(&omap4_idle_driver); + if (cpuidle_register_driver(&omap4_idle_driver)) { + pr_err("%s: CPUidle driver register failed\n", __func__); + return -EIO; + } for_each_cpu(cpu_id, cpu_online_mask) { dev = &per_cpu(omap4_idle_dev, cpu_id); @@ -232,6 +235,7 @@ int __init omap4_idle_init(void) #endif if (cpuidle_register_device(dev)) { pr_err("%s: CPUidle register failed\n", __func__); + cpuidle_unregister_driver(&omap4_idle_driver); return -EIO; } } -- cgit v0.10.2 From eb495d33558d065ad316b3bb21ebd7e81da1891e Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Mon, 25 Mar 2013 15:35:06 +0530 Subject: ARM: OMAP4: CPUidle: Make C-state description field more precise It is useful to know the CPU power state along with MPUSS power state in a supported C-state. Since the data is available via sysfs, one can avoid scrolling the source code for precise construction of C-state. Reported-by: Nishanth Menon Acked-by: Nishanth Menon Signed-off-by: Santosh Shilimkar Signed-off-by: Kevin Hilman diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index aeeb8e6..e48e26e 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -171,7 +171,7 @@ static struct cpuidle_driver omap4_idle_driver = { .flags = CPUIDLE_FLAG_TIME_VALID, .enter = omap4_enter_idle_simple, .name = "C1", - .desc = "MPUSS ON" + .desc = "CPUx ON, MPUSS ON" }, { /* C2 - CPU0 OFF + CPU1 OFF + MPU CSWR */ @@ -181,7 +181,7 @@ static struct cpuidle_driver omap4_idle_driver = { CPUIDLE_FLAG_TIMER_STOP, .enter = omap4_enter_idle_coupled, .name = "C2", - .desc = "MPUSS CSWR", + .desc = "CPUx OFF, MPUSS CSWR", }, { /* C3 - CPU0 OFF + CPU1 OFF + MPU OSWR */ @@ -191,7 +191,7 @@ static struct cpuidle_driver omap4_idle_driver = { CPUIDLE_FLAG_TIMER_STOP, .enter = omap4_enter_idle_coupled, .name = "C3", - .desc = "MPUSS OSWR", + .desc = "CPUx OFF, MPUSS OSWR", }, }, .state_count = ARRAY_SIZE(omap4_idle_data), -- cgit v0.10.2 From e7457253494fff660a72bc0cedeee97491ccd173 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Mon, 25 Mar 2013 15:35:08 +0530 Subject: ARM: OMAP4+: CPUidle: Deprecate use of omap4_mpuss_read_prev_context_state() Current OMAP4 CPUIdle driver is using omap4_mpuss_read_prev_context_state() to check whether the MPU cluster lost context or not before calling cpu_cluster_pm_exit(). This was initially done an optimization for corner cases, where if the cluster low power entry fails for some reason, the cluster context restore gets skipped. However, since reading the previous context is expensive (involving slow accesses to the PRCM), it's better to avoid it and simply check the target cluster state instead. Moving forward, OMAP CPUidle drivers needs to be moved to drivers/idle/* once the PRM/CM code gets moved to drivers. This patch also reduces one dependency with platform code for idle driver movement. Acked-by: Nishanth Menon Signed-off-by: Santosh Shilimkar [khilman@linaro.org: minor changelog edits] Signed-off-by: Kevin Hilman diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index d6ba13e..14522d0 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -249,7 +249,6 @@ extern int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state); extern int omap4_finish_suspend(unsigned long cpu_state); extern void omap4_cpu_resume(void); extern int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state); -extern u32 omap4_mpuss_read_prev_context_state(void); #else static inline int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) @@ -277,10 +276,6 @@ static inline int omap4_finish_suspend(unsigned long cpu_state) static inline void omap4_cpu_resume(void) {} -static inline u32 omap4_mpuss_read_prev_context_state(void) -{ - return 0; -} #endif struct omap_sdrc_params; diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index e48e26e..e72b55d 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -145,7 +145,8 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev, * Call idle CPU cluster PM exit notifier chain * to restore GIC and wakeupgen context. */ - if (omap4_mpuss_read_prev_context_state()) + if ((cx->mpu_state == PWRDM_POWER_RET) && + (cx->mpu_logic_state == PWRDM_POWER_OFF)) cpu_cluster_pm_exit(); fail: diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c index 8bcb64b..e80327b 100644 --- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c +++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c @@ -139,20 +139,6 @@ static inline void cpu_clear_prev_logic_pwrst(unsigned int cpu_id) } } -/** - * omap4_mpuss_read_prev_context_state: - * Function returns the MPUSS previous context state - */ -u32 omap4_mpuss_read_prev_context_state(void) -{ - u32 reg; - - reg = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, - OMAP4430_PRM_MPU_INST, OMAP4_RM_MPU_MPU_CONTEXT_OFFSET); - reg &= OMAP4430_LOSTCONTEXT_DFF_MASK; - return reg; -} - /* * Store the CPU cluster state for L2X0 low power operations. */ -- cgit v0.10.2 From db4f3dab629109882170a7b1b8fb655a34c52846 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Fri, 5 Apr 2013 18:29:03 +0530 Subject: ARM: OMAP4+: CPUidle: Consolidate idle driver for OMAP5 support The OMAP5 idle driver can re-use most of OMAP4 CPUidle driver implementation. Also the next derivative SOCs are going to re-use the MPUSS so, same driver with minor updates can be re-used. Prepare the code so that its easier to add CPUidle support for OMAP5 devices. Acked-by: Nishanth Menon Signed-off-by: Santosh Shilimkar Signed-off-by: Kevin Hilman diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index e72b55d..8a0e43c 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -1,7 +1,7 @@ /* - * OMAP4 CPU idle Routines + * OMAP4+ CPU idle Routines * - * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011-2013 Texas Instruments, Inc. * Santosh Shilimkar * Rajendra Nayak * @@ -23,13 +23,13 @@ #include "clockdomain.h" /* Machine specific information */ -struct omap4_idle_statedata { +struct idle_statedata { u32 cpu_state; u32 mpu_logic_state; u32 mpu_state; }; -static struct omap4_idle_statedata omap4_idle_data[] = { +static struct idle_statedata omap4_idle_data[] = { { .cpu_state = PWRDM_POWER_ON, .mpu_state = PWRDM_POWER_ON, @@ -52,11 +52,12 @@ static struct clockdomain *cpu_clkdm[NR_CPUS]; static atomic_t abort_barrier; static bool cpu_done[NR_CPUS]; +static struct idle_statedata *state_ptr = &omap4_idle_data[0]; /* Private functions */ /** - * omap4_enter_idle_coupled_[simple/coupled] - OMAP4 cpuidle entry functions + * omap_enter_idle_[simple/coupled] - OMAP4PLUS cpuidle entry functions * @dev: cpuidle device * @drv: cpuidle driver * @index: the index of state to be entered @@ -65,7 +66,7 @@ static bool cpu_done[NR_CPUS]; * specified low power state selected by the governor. * Returns the amount of time spent in the low power state. */ -static int omap4_enter_idle_simple(struct cpuidle_device *dev, +static int omap_enter_idle_simple(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { @@ -76,11 +77,11 @@ static int omap4_enter_idle_simple(struct cpuidle_device *dev, return index; } -static int omap4_enter_idle_coupled(struct cpuidle_device *dev, +static int omap_enter_idle_coupled(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { - struct omap4_idle_statedata *cx = &omap4_idle_data[index]; + struct idle_statedata *cx = state_ptr + index; local_fiq_disable(); @@ -158,7 +159,7 @@ fail: return index; } -static DEFINE_PER_CPU(struct cpuidle_device, omap4_idle_dev); +static DEFINE_PER_CPU(struct cpuidle_device, omap_idle_dev); static struct cpuidle_driver omap4_idle_driver = { .name = "omap4_idle", @@ -170,7 +171,7 @@ static struct cpuidle_driver omap4_idle_driver = { .exit_latency = 2 + 2, .target_residency = 5, .flags = CPUIDLE_FLAG_TIME_VALID, - .enter = omap4_enter_idle_simple, + .enter = omap_enter_idle_simple, .name = "C1", .desc = "CPUx ON, MPUSS ON" }, @@ -180,7 +181,7 @@ static struct cpuidle_driver omap4_idle_driver = { .target_residency = 960, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED | CPUIDLE_FLAG_TIMER_STOP, - .enter = omap4_enter_idle_coupled, + .enter = omap_enter_idle_coupled, .name = "C2", .desc = "CPUx OFF, MPUSS CSWR", }, @@ -190,7 +191,7 @@ static struct cpuidle_driver omap4_idle_driver = { .target_residency = 1100, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED | CPUIDLE_FLAG_TIMER_STOP, - .enter = omap4_enter_idle_coupled, + .enter = omap_enter_idle_coupled, .name = "C3", .desc = "CPUx OFF, MPUSS OSWR", }, @@ -202,9 +203,9 @@ static struct cpuidle_driver omap4_idle_driver = { /* Public functions */ /** - * omap4_idle_init - Init routine for OMAP4 idle + * omap4_idle_init - Init routine for OMAP4+ idle * - * Registers the OMAP4 specific cpuidle driver to the cpuidle + * Registers the OMAP4+ specific cpuidle driver to the cpuidle * framework with the valid set of states. */ int __init omap4_idle_init(void) @@ -229,7 +230,7 @@ int __init omap4_idle_init(void) } for_each_cpu(cpu_id, cpu_online_mask) { - dev = &per_cpu(omap4_idle_dev, cpu_id); + dev = &per_cpu(omap_idle_dev, cpu_id); dev->cpu = cpu_id; #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED dev->coupled_cpus = *cpu_online_mask; -- cgit v0.10.2 From 94b4624986071a875871378f2a84e3f816764372 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 22 Apr 2013 00:21:29 +0200 Subject: intel_idle: remove stop/start critical timings The start/stop_critical_timings are called from arch/x86/kernel/process.c in the cpu_idle loop function. Remove the ones in the cpuidle driver. Signed-off-by: Daniel Lezcano Acked-by: Len Brown Signed-off-by: Rafael J. Wysocki diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 5d66750..c99c31e 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -339,7 +339,6 @@ static int intel_idle(struct cpuidle_device *dev, if (!(lapic_timer_reliable_states & (1 << (cstate)))) clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); - stop_critical_timings(); if (!need_resched()) { __monitor((void *)¤t_thread_info()->flags, 0, 0); @@ -348,8 +347,6 @@ static int intel_idle(struct cpuidle_device *dev, __mwait(eax, ecx); } - start_critical_timings(); - if (!(lapic_timer_reliable_states & (1 << (cstate)))) clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); -- cgit v0.10.2 From 055d752f85f18abb2ad7e2193f61afefe36fd452 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 17 Apr 2013 13:32:54 +0000 Subject: SH: cpuidle: remove pointless initialization The driver is a global static variable automatically initialized to zero. Removing the useless initialization in the init function. Signed-off-by: Daniel Lezcano Acked-by: Simon Horman Signed-off-by: Rafael J. Wysocki diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c index 1ddc876..34bb546 100644 --- a/arch/sh/kernel/cpu/shmobile/cpuidle.c +++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c @@ -65,12 +65,6 @@ void sh_mobile_setup_cpuidle(void) struct cpuidle_state *state; int i; - - for (i = 0; i < CPUIDLE_STATE_MAX; i++) { - drv->states[i].name[0] = '\0'; - drv->states[i].desc[0] = '\0'; - } - i = CPUIDLE_DRIVER_STATE_START; state = &drv->states[i++]; -- cgit v0.10.2 From 194db92fd20cd7733f1ee06b330af93e10dfe727 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 17 Apr 2013 13:32:55 +0000 Subject: SH: cpuidle: remove CPUIDLE_DRIVER_STATE_START usage The CPUIDLE_DRIVER_STATE_START constant is only set when the kernel compilation option CONFIG_ARCH_HAS_CPU_RELAX is set, but this is only relatated to x86, so it is always zero. Remove the reference to this constant in the code. Signed-off-by: Daniel Lezcano Acked-by: Simon Horman Signed-off-by: Rafael J. Wysocki diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c index 34bb546..4b27701 100644 --- a/arch/sh/kernel/cpu/shmobile/cpuidle.c +++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c @@ -63,9 +63,7 @@ void sh_mobile_setup_cpuidle(void) struct cpuidle_device *dev = &cpuidle_dev; struct cpuidle_driver *drv = &cpuidle_driver; struct cpuidle_state *state; - int i; - - i = CPUIDLE_DRIVER_STATE_START; + int i = 0; state = &drv->states[i++]; snprintf(state->name, CPUIDLE_NAME_LEN, "C1"); @@ -77,7 +75,7 @@ void sh_mobile_setup_cpuidle(void) state->flags |= CPUIDLE_FLAG_TIME_VALID; state->enter = cpuidle_sleep_enter; - drv->safe_state_index = i-1; + drv->safe_state_index = 0; if (sh_mobile_sleep_supported & SUSP_SH_SF) { state = &drv->states[i++]; -- cgit v0.10.2 From 0a4f841e9c473be84a1ed0c14f65058c29238ce1 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 17 Apr 2013 13:32:56 +0000 Subject: SH: cpuidle: initialize the driver's states directly Like all the other drivers, let's initialize the structure a compile time instead of init time. The states #1 and #2 are not enabled by default. The init function will check the features of the board in order to enable the state. Signed-off-by: Daniel Lezcano Acked-by: Simon Horman Signed-off-by: Rafael J. Wysocki diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c index 4b27701..aae3468 100644 --- a/arch/sh/kernel/cpu/shmobile/cpuidle.c +++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c @@ -53,60 +53,52 @@ static int cpuidle_sleep_enter(struct cpuidle_device *dev, static struct cpuidle_device cpuidle_dev; static struct cpuidle_driver cpuidle_driver = { - .name = "sh_idle", - .owner = THIS_MODULE, - .en_core_tk_irqen = 1, + .name = "sh_idle", + .owner = THIS_MODULE, + .en_core_tk_irqen = 1, + .states = { + { + .exit_latency = 1, + .target_residency = 1 * 2, + .power_usage = 3, + .flags = CPUIDLE_FLAG_TIME_VALID, + .enter = cpuidle_sleep_enter, + .name = "C1", + .desc = "SuperH Sleep Mode", + }, + { + .exit_latency = 100, + .target_residency = 1 * 2, + .power_usage = 1, + .flags = CPUIDLE_FLAG_TIME_VALID, + .enter = cpuidle_sleep_enter, + .name = "C2", + .desc = "SuperH Sleep Mode [SF]", + .disabled = true, + }, + { + .exit_latency = 2300, + .target_residency = 1 * 2, + .power_usage = 1, + .flags = CPUIDLE_FLAG_TIME_VALID, + .enter = cpuidle_sleep_enter, + .name = "C3", + .desc = "SuperH Mobile Standby Mode [SF]", + .disabled = true, + }, + }, + .safe_state_index = 0, + .state_count = 3, }; void sh_mobile_setup_cpuidle(void) { - struct cpuidle_device *dev = &cpuidle_dev; - struct cpuidle_driver *drv = &cpuidle_driver; - struct cpuidle_state *state; - int i = 0; + if (sh_mobile_sleep_supported & SUSP_SH_SF) + cpuidle_driver.states[1].disabled = false; - state = &drv->states[i++]; - snprintf(state->name, CPUIDLE_NAME_LEN, "C1"); - strncpy(state->desc, "SuperH Sleep Mode", CPUIDLE_DESC_LEN); - state->exit_latency = 1; - state->target_residency = 1 * 2; - state->power_usage = 3; - state->flags = 0; - state->flags |= CPUIDLE_FLAG_TIME_VALID; - state->enter = cpuidle_sleep_enter; + if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) + cpuidle_driver.states[2].disabled = false; - drv->safe_state_index = 0; - - if (sh_mobile_sleep_supported & SUSP_SH_SF) { - state = &drv->states[i++]; - snprintf(state->name, CPUIDLE_NAME_LEN, "C2"); - strncpy(state->desc, "SuperH Sleep Mode [SF]", - CPUIDLE_DESC_LEN); - state->exit_latency = 100; - state->target_residency = 1 * 2; - state->power_usage = 1; - state->flags = 0; - state->flags |= CPUIDLE_FLAG_TIME_VALID; - state->enter = cpuidle_sleep_enter; - } - - if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) { - state = &drv->states[i++]; - snprintf(state->name, CPUIDLE_NAME_LEN, "C3"); - strncpy(state->desc, "SuperH Mobile Standby Mode [SF]", - CPUIDLE_DESC_LEN); - state->exit_latency = 2300; - state->target_residency = 1 * 2; - state->power_usage = 1; - state->flags = 0; - state->flags |= CPUIDLE_FLAG_TIME_VALID; - state->enter = cpuidle_sleep_enter; - } - - drv->state_count = i; - dev->state_count = i; - - cpuidle_register_driver(&cpuidle_driver); - - cpuidle_register_device(dev); + if (!cpuidle_register_driver(&cpuidle_driver)) + cpuidle_register_device(&cpuidle_dev); } -- cgit v0.10.2 From 38a94f4169e03494cbf850919b4b0a7e53e84bfd Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 17 Apr 2013 13:32:57 +0000 Subject: SH: cpuidle: check error code at init Registering the driver, or the device, can fail, let's check the return code and return the error code to the PM layer. Signed-off-by: Daniel Lezcano Acked-by: Simon Horman Signed-off-by: Rafael J. Wysocki diff --git a/arch/sh/include/asm/suspend.h b/arch/sh/include/asm/suspend.h index e14567a..70ae0b2 100644 --- a/arch/sh/include/asm/suspend.h +++ b/arch/sh/include/asm/suspend.h @@ -14,9 +14,9 @@ struct swsusp_arch_regs { void sh_mobile_call_standby(unsigned long mode); #ifdef CONFIG_CPU_IDLE -void sh_mobile_setup_cpuidle(void); +int sh_mobile_setup_cpuidle(void); #else -static inline void sh_mobile_setup_cpuidle(void) {} +static inline int sh_mobile_setup_cpuidle(void) { return 0; } #endif /* notifier chains for pre/post sleep hooks */ diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c index aae3468..ea6ab02 100644 --- a/arch/sh/kernel/cpu/shmobile/cpuidle.c +++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c @@ -91,14 +91,19 @@ static struct cpuidle_driver cpuidle_driver = { .state_count = 3, }; -void sh_mobile_setup_cpuidle(void) +int __init sh_mobile_setup_cpuidle(void) { + int ret; + if (sh_mobile_sleep_supported & SUSP_SH_SF) cpuidle_driver.states[1].disabled = false; if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) cpuidle_driver.states[2].disabled = false; - if (!cpuidle_register_driver(&cpuidle_driver)) - cpuidle_register_device(&cpuidle_dev); + ret = cpuidle_register_driver(&cpuidle_driver); + if (ret) + return ret; + + return cpuidle_register_device(&cpuidle_dev); } diff --git a/arch/sh/kernel/cpu/shmobile/pm.c b/arch/sh/kernel/cpu/shmobile/pm.c index 08d27fa..ac37b72 100644 --- a/arch/sh/kernel/cpu/shmobile/pm.c +++ b/arch/sh/kernel/cpu/shmobile/pm.c @@ -150,8 +150,7 @@ static const struct platform_suspend_ops sh_pm_ops = { static int __init sh_pm_init(void) { suspend_set_ops(&sh_pm_ops); - sh_mobile_setup_cpuidle(); - return 0; + return sh_mobile_setup_cpuidle(); } late_initcall(sh_pm_init); -- cgit v0.10.2 From 38ef8d3fa4a67c07bdfd640833a88baf525f955b Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 12 Apr 2013 12:35:47 +0000 Subject: ARM: shmobile: cpuidle: remove shmobile_enter_wfi function Remove the shmobile_enter_wfi function which is the same as the common WFI enter function from the arm cpuidle driver defined with the ARM_CPUIDLE_WFI_STATE macro. Signed-off-by: Daniel Lezcano Acked-by: Simon Horman Acked-by: Santosh Shilimkar Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c index f6b14ca..fbef7b9 100644 --- a/arch/arm/mach-shmobile/pm-sh7372.c +++ b/arch/arm/mach-shmobile/pm-sh7372.c @@ -414,7 +414,6 @@ static struct cpuidle_driver sh7372_cpuidle_driver = { .state_count = 5, .safe_state_index = 0, /* C1 */ .states[0] = ARM_CPUIDLE_WFI_STATE, - .states[0].enter = shmobile_enter_wfi, .states[1] = { .name = "C2", .desc = "Core Standby Mode", -- cgit v0.10.2 From 80d538b2754f1eed85296f0c7088f7157d543f89 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 12 Apr 2013 12:35:48 +0000 Subject: ARM: shmobile: cpuidle: remove shmobile_enter_wfi prototype Commit 688036b538974de32ce55be8b0e013b003992abc removed the function 'shmobile_enter_wfi' but we forgot to remove the definition in the header file. Note this function is just an alias to 'cpu_do_idle()' wrapped into a cpuidle function callback prototype which already exists with the default WFI state and the arm_simple_enter function. Remove the function prototype. Signed-off-by: Daniel Lezcano Acked-by: Simon Horman Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index e48606d..362f9b2 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -13,9 +13,6 @@ extern int shmobile_clk_init(void); extern void shmobile_handle_irq_intc(struct pt_regs *); extern struct platform_suspend_ops shmobile_suspend_ops; struct cpuidle_driver; -struct cpuidle_device; -extern int shmobile_enter_wfi(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int index); extern void shmobile_cpuidle_set_driver(struct cpuidle_driver *drv); extern void sh7372_init_irq(void); -- cgit v0.10.2 From 3dcb9f1b17879534c80ccbf62fd13156f83ef799 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 12 Apr 2013 12:35:49 +0000 Subject: ARM: OMAP3: remove cpuidle_wrap_enter In a previous commit the en_core_tk_irqen flag has been added but we missed the cpuidle_wrap_enter which was doing the job to measure the time for the 'omap3_enter_idle' function. Actually, I don't see any reason to use this wrapper in the code. In the better case, the time computation is not correctly done because of the different operations done in omap3_enter_idle_bm which were not taken into account before the en_core_tk_irqen flag was set. As the time is reflected for the state overridden by the omap3_enter_idle_bm, using the wrapper is pointless now, so removing it. Signed-off-by: Daniel Lezcano Acked-by: Kevin Hilman Acked-by: Santosh Shilimkar Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index a300122..0ee39a8 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -99,11 +99,15 @@ static struct omap3_idle_statedata omap3_idle_data[] = { }, }; -/* Private functions */ - -static int __omap3_enter_idle(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int 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 + */ +static int omap3_enter_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) { struct omap3_idle_statedata *cx = &omap3_idle_data[index]; @@ -149,22 +153,6 @@ return_sleep_time: } /** - * 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 -- cgit v0.10.2 From 554c06ba3ee29cf453fca17e9e61120b75aa476d Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 23 Apr 2013 08:54:31 +0000 Subject: cpuidle: remove en_core_tk_irqen flag The en_core_tk_irqen flag is set in all the cpuidle driver which means it is not necessary to specify this flag. Remove the flag and the code related to it. Signed-off-by: Daniel Lezcano Acked-by: Kevin Hilman # for mach-omap2/* Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c index 0c63815..0130df7 100644 --- a/arch/arm/mach-at91/cpuidle.c +++ b/arch/arm/mach-at91/cpuidle.c @@ -47,7 +47,6 @@ static int at91_enter_idle(struct cpuidle_device *dev, 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, diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c index 22d6d4a..c2887c5 100644 --- a/arch/arm/mach-davinci/cpuidle.c +++ b/arch/arm/mach-davinci/cpuidle.c @@ -62,7 +62,6 @@ static int davinci_enter_idle(struct cpuidle_device *dev, static struct cpuidle_driver davinci_idle_driver = { .name = "cpuidle-davinci", .owner = THIS_MODULE, - .en_core_tk_irqen = 1, .states[0] = ARM_CPUIDLE_WFI_STATE, .states[1] = { .enter = davinci_enter_idle, diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index fcfe025..498a7a2 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -58,7 +58,6 @@ static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device); static struct cpuidle_driver exynos4_idle_driver = { .name = "exynos4_idle", .owner = THIS_MODULE, - .en_core_tk_irqen = 1, }; /* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */ diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c index a783a63..e2739ad 100644 --- a/arch/arm/mach-imx/cpuidle-imx6q.c +++ b/arch/arm/mach-imx/cpuidle-imx6q.c @@ -45,7 +45,6 @@ done: static struct cpuidle_driver imx6q_cpuidle_driver = { .name = "imx6q_cpuidle", .owner = THIS_MODULE, - .en_core_tk_irqen = 1, .states = { /* WFI */ ARM_CPUIDLE_WFI_STATE, diff --git a/arch/arm/mach-imx/pm-imx5.c b/arch/arm/mach-imx/pm-imx5.c index f67fd7e..4b52b3e 100644 --- a/arch/arm/mach-imx/pm-imx5.c +++ b/arch/arm/mach-imx/pm-imx5.c @@ -164,7 +164,6 @@ static int imx5_cpuidle_enter(struct cpuidle_device *dev, static struct cpuidle_driver imx5_cpuidle_driver = { .name = "imx5_cpuidle", .owner = THIS_MODULE, - .en_core_tk_irqen = 1, .states[0] = { .enter = imx5_cpuidle_enter, .exit_latency = 2, diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 0ee39a8..20785b2 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -264,7 +264,6 @@ static DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev); static struct cpuidle_driver omap3_idle_driver = { .name = "omap3_idle", .owner = THIS_MODULE, - .en_core_tk_irqen = 1, .states = { { .enter = omap3_enter_idle_bm, diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index 8a0e43c..d1bfb21 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -164,7 +164,6 @@ static DEFINE_PER_CPU(struct cpuidle_device, omap_idle_dev); static struct cpuidle_driver omap4_idle_driver = { .name = "omap4_idle", .owner = THIS_MODULE, - .en_core_tk_irqen = 1, .states = { { /* C1 - CPU0 ON + CPU1 ON + MPU ON */ diff --git a/arch/arm/mach-s3c64xx/cpuidle.c b/arch/arm/mach-s3c64xx/cpuidle.c index ead5fab..852ff16 100644 --- a/arch/arm/mach-s3c64xx/cpuidle.c +++ b/arch/arm/mach-s3c64xx/cpuidle.c @@ -45,7 +45,6 @@ static DEFINE_PER_CPU(struct cpuidle_device, s3c64xx_cpuidle_device); static struct cpuidle_driver s3c64xx_cpuidle_driver = { .name = "s3c64xx_cpuidle", .owner = THIS_MODULE, - .en_core_tk_irqen = 1, .states = { { .enter = s3c64xx_enter_idle, diff --git a/arch/arm/mach-shmobile/cpuidle.c b/arch/arm/mach-shmobile/cpuidle.c index c872ae8..d671ae9 100644 --- a/arch/arm/mach-shmobile/cpuidle.c +++ b/arch/arm/mach-shmobile/cpuidle.c @@ -20,7 +20,6 @@ static struct cpuidle_device shmobile_cpuidle_dev; static struct cpuidle_driver shmobile_cpuidle_default_driver = { .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, diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c index fbef7b9..dec9293 100644 --- a/arch/arm/mach-shmobile/pm-sh7372.c +++ b/arch/arm/mach-shmobile/pm-sh7372.c @@ -410,7 +410,6 @@ static int sh7372_enter_a4s(struct cpuidle_device *dev, static struct cpuidle_driver sh7372_cpuidle_driver = { .name = "sh7372_cpuidle", .owner = THIS_MODULE, - .en_core_tk_irqen = 1, .state_count = 5, .safe_state_index = 0, /* C1 */ .states[0] = ARM_CPUIDLE_WFI_STATE, diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c index c527cff..c5fadf9 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra114.c +++ b/arch/arm/mach-tegra/cpuidle-tegra114.c @@ -23,7 +23,6 @@ static struct cpuidle_driver tegra_idle_driver = { .name = "tegra_idle", .owner = THIS_MODULE, - .en_core_tk_irqen = 1, .state_count = 1, .states = { [0] = ARM_CPUIDLE_WFI_STATE_PWR(600), diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c index b94d76a..f1f6ac4 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra20.c +++ b/arch/arm/mach-tegra/cpuidle-tegra20.c @@ -51,7 +51,6 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev, static struct cpuidle_driver tegra_idle_driver = { .name = "tegra_idle", .owner = THIS_MODULE, - .en_core_tk_irqen = 1, .states = { ARM_CPUIDLE_WFI_STATE_PWR(600), #ifdef CONFIG_PM_SLEEP diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c index c4e01fe..f6a0c72 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra30.c +++ b/arch/arm/mach-tegra/cpuidle-tegra30.c @@ -43,7 +43,6 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev, static struct cpuidle_driver tegra_idle_driver = { .name = "tegra_idle", .owner = THIS_MODULE, - .en_core_tk_irqen = 1, #ifdef CONFIG_PM_SLEEP .state_count = 2, #else diff --git a/arch/arm/mach-ux500/cpuidle.c b/arch/arm/mach-ux500/cpuidle.c index 1b16d9e..c29c1bf 100644 --- a/arch/arm/mach-ux500/cpuidle.c +++ b/arch/arm/mach-ux500/cpuidle.c @@ -94,7 +94,6 @@ out: static struct cpuidle_driver ux500_idle_driver = { .name = "ux500_idle", .owner = THIS_MODULE, - .en_core_tk_irqen = 1, .states = { ARM_CPUIDLE_WFI_STATE, { diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c index a197120..4644efa0 100644 --- a/arch/powerpc/platforms/pseries/processor_idle.c +++ b/arch/powerpc/platforms/pseries/processor_idle.c @@ -25,7 +25,6 @@ struct cpuidle_driver pseries_idle_driver = { .name = "pseries_idle", .owner = THIS_MODULE, - .en_core_tk_irqen = 1, }; #define MAX_IDLE_STATE_COUNT 2 diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c index ea6ab02..fdfe57f4 100644 --- a/arch/sh/kernel/cpu/shmobile/cpuidle.c +++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c @@ -55,7 +55,6 @@ static struct cpuidle_device cpuidle_dev; static struct cpuidle_driver cpuidle_driver = { .name = "sh_idle", .owner = THIS_MODULE, - .en_core_tk_irqen = 1, .states = { { .exit_latency = 1, diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index 66b5faf..53a4e27 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -373,7 +373,6 @@ static int apm_cpu_idle(struct cpuidle_device *dev, static struct cpuidle_driver apm_idle_driver = { .name = "apm_idle", .owner = THIS_MODULE, - .en_core_tk_irqen = 1, .states = { { /* entry 0 is for polling */ }, { /* entry 1 is for APM idle */ diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index ee255c6..f0df2c9 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -918,7 +918,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, struct cpuidle_driver acpi_idle_driver = { .name = "acpi_idle", .owner = THIS_MODULE, - .en_core_tk_irqen = 1, }; /** diff --git a/drivers/cpuidle/cpuidle-calxeda.c b/drivers/cpuidle/cpuidle-calxeda.c index e1aab38..a3b56f5 100644 --- a/drivers/cpuidle/cpuidle-calxeda.c +++ b/drivers/cpuidle/cpuidle-calxeda.c @@ -100,7 +100,6 @@ static void calxeda_idle_cpuidle_devices_uninit(void) static struct cpuidle_driver calxeda_idle_driver = { .name = "calxeda_idle", - .en_core_tk_irqen = 1, .states = { ARM_CPUIDLE_WFI_STATE, { diff --git a/drivers/cpuidle/cpuidle-kirkwood.c b/drivers/cpuidle/cpuidle-kirkwood.c index 53aad73..6f31524 100644 --- a/drivers/cpuidle/cpuidle-kirkwood.c +++ b/drivers/cpuidle/cpuidle-kirkwood.c @@ -41,7 +41,6 @@ static int kirkwood_enter_idle(struct cpuidle_device *dev, 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, diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index c500370..0da795b 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -43,24 +43,6 @@ void disable_cpuidle(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_play_dead - cpu off-lining * @@ -90,11 +72,27 @@ int cpuidle_play_dead(void) * @next_state: index into drv->states of the state to enter */ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, - int next_state) + int index) { int entered_state; - entered_state = cpuidle_enter_ops(dev, drv, next_state); + struct cpuidle_state *target_state = &drv->states[index]; + ktime_t time_start, time_end; + s64 diff; + + time_start = ktime_get(); + + entered_state = target_state->enter(dev, drv, index); + + time_end = ktime_get(); + + local_irq_enable(); + + diff = ktime_to_us(ktime_sub(time_end, time_start)); + if (diff > INT_MAX) + diff = INT_MAX; + + dev->last_residency = (int) diff; if (entered_state >= 0) { /* Update cpuidle counters */ @@ -231,37 +229,6 @@ void cpuidle_resume(void) mutex_unlock(&cpuidle_lock); } -/** - * 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 time_start, time_end; - s64 diff; - - time_start = ktime_get(); - - index = enter(dev, drv, index); - - time_end = ktime_get(); - - local_irq_enable(); - - diff = ktime_to_us(ktime_sub(time_end, time_start)); - if (diff > INT_MAX) - diff = INT_MAX; - - dev->last_residency = (int) diff; - - return index; -} - #ifdef CONFIG_ARCH_HAS_CPU_RELAX static int poll_idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) @@ -333,9 +300,6 @@ int cpuidle_enable_device(struct cpuidle_device *dev) return ret; } - cpuidle_enter_ops = drv->en_core_tk_irqen ? - cpuidle_enter_tk : cpuidle_enter; - poll_idle_init(drv); ret = cpuidle_add_device_sysfs(dev); diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index c99c31e..6f80c13 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -71,7 +71,6 @@ static struct cpuidle_driver intel_idle_driver = { .name = "intel_idle", .owner = THIS_MODULE, - .en_core_tk_irqen = 1, }; /* intel_idle.max_cstate=0 disables driver */ static int max_cstate = CPUIDLE_STATE_MAX - 1; diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index fc3e580..79e3811 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -105,8 +105,6 @@ struct cpuidle_driver { struct module *owner; int refcnt; - /* set to 1 to use the core cpuidle time keeping (for all states). */ - unsigned int en_core_tk_irqen:1; /* used by the cpuidle framework to setup the broadcast timer */ unsigned int bctimer:1; /* states array must be ordered in decreasing power consumption */ @@ -132,10 +130,6 @@ extern void cpuidle_pause(void); extern void cpuidle_resume(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)); extern int cpuidle_play_dead(void); extern struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev); @@ -162,11 +156,6 @@ static inline void cpuidle_resume(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; } static inline int cpuidle_play_dead(void) {return -ENODEV; } #endif -- cgit v0.10.2 From 80b1c1999edbba3a411335f1650f0d92da391516 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 23 Apr 2013 08:54:32 +0000 Subject: ARM: ux500: cpuidle: replace for_each_online_cpu by for_each_possible_cpu All the drivers are using, in their initialization function, the for_each_possible_cpu macro. Using for_each_online_cpu means the driver must handle the initialization of the cpuidle device when a cpu is up which is not the case here. Change the macro to for_each_possible_cpu as that fix the hotplug initialization and make the initialization routine consistent with the rest of the code in the different drivers. Signed-off-by: Daniel Lezcano Acked-by: Linus Walleij Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-ux500/cpuidle.c b/arch/arm/mach-ux500/cpuidle.c index c29c1bf..5657d4a 100644 --- a/arch/arm/mach-ux500/cpuidle.c +++ b/arch/arm/mach-ux500/cpuidle.c @@ -125,7 +125,7 @@ int __init ux500_idle_init(void) return ret; } - for_each_online_cpu(cpu) { + for_each_possible(cpu) { device = &per_cpu(ux500_cpuidle_device, cpu); device->cpu = cpu; ret = cpuidle_register_device(device); @@ -139,7 +139,7 @@ out: return ret; out_unregister: - for_each_online_cpu(cpu) { + for_each_possible_cpu(cpu) { device = &per_cpu(ux500_cpuidle_device, cpu); cpuidle_unregister_device(device); } -- cgit v0.10.2 From 4c637b2175a0dc65d533494225525c6c82d73293 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 23 Apr 2013 08:54:33 +0000 Subject: cpuidle: make a single register function for all 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); } 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. Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki 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); +/* + * 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 + 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) { } -- cgit v0.10.2 From e8928e2e1ec2e3325a90bcc19746ea67cc4bb083 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 23 Apr 2013 08:54:34 +0000 Subject: ARM: ux500: cpuidle: use init/exit common routine Remove the duplicate code and use the cpuidle common code for initialization. Signed-off-by: Daniel Lezcano Acked-by: Linus Walleij Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-ux500/cpuidle.c b/arch/arm/mach-ux500/cpuidle.c index 5657d4a..488e074 100644 --- a/arch/arm/mach-ux500/cpuidle.c +++ b/arch/arm/mach-ux500/cpuidle.c @@ -21,7 +21,6 @@ static atomic_t master = ATOMIC_INIT(0); static DEFINE_SPINLOCK(master_lock); -static DEFINE_PER_CPU(struct cpuidle_device, ux500_cpuidle_device); static inline int ux500_enter_idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) @@ -112,40 +111,11 @@ static struct cpuidle_driver ux500_idle_driver = { int __init ux500_idle_init(void) { - int ret, cpu; - struct cpuidle_device *device; - /* Configure wake up reasons */ prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) | PRCMU_WAKEUP(ABB)); - ret = cpuidle_register_driver(&ux500_idle_driver); - if (ret) { - printk(KERN_ERR "failed to register ux500 idle driver\n"); - return ret; - } - - for_each_possible(cpu) { - device = &per_cpu(ux500_cpuidle_device, cpu); - device->cpu = cpu; - ret = cpuidle_register_device(device); - if (ret) { - printk(KERN_ERR "Failed to register cpuidle " - "device for cpu%d\n", cpu); - goto out_unregister; - } - } -out: - return ret; - -out_unregister: - for_each_possible_cpu(cpu) { - device = &per_cpu(ux500_cpuidle_device, cpu); - cpuidle_unregister_device(device); - } - - cpuidle_unregister_driver(&ux500_idle_driver); - goto out; + return cpuidle_register(&ux500_idle_driver, NULL); } device_initcall(ux500_idle_init); -- cgit v0.10.2 From 22f5d1fa0886355ab8a1a25978c43905ad7a4ec5 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 23 Apr 2013 08:54:35 +0000 Subject: ARM: at91: cpuidle: use init/exit common routine Remove the duplicated code and use the cpuidle common code for initialization. Signed-off-by: Daniel Lezcano Acked-by: Nicolas Ferre Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c index 0130df7..48f1228 100644 --- a/arch/arm/mach-at91/cpuidle.c +++ b/arch/arm/mach-at91/cpuidle.c @@ -27,8 +27,6 @@ #define AT91_MAX_STATES 2 -static DEFINE_PER_CPU(struct cpuidle_device, at91_cpuidle_device); - /* Actual code that puts the SoC in different idle states */ static int at91_enter_idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, @@ -60,20 +58,9 @@ static struct cpuidle_driver at91_idle_driver = { }; /* Initialize CPU idle by registering the idle states */ -static int at91_init_cpuidle(void) +static int __init at91_init_cpuidle(void) { - struct cpuidle_device *device; - - device = &per_cpu(at91_cpuidle_device, smp_processor_id()); - device->state_count = AT91_MAX_STATES; - - cpuidle_register_driver(&at91_idle_driver); - - if (cpuidle_register_device(device)) { - printk(KERN_ERR "at91_init_cpuidle: Failed registering\n"); - return -EIO; - } - return 0; + return cpuidle_register(&at91_idle_driver, NULL); } device_initcall(at91_init_cpuidle); -- cgit v0.10.2 From 472a85f762da0cf4c72d216b13342e8c15c86bc8 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 23 Apr 2013 08:54:36 +0000 Subject: ARM: OMAP3: cpuidle: use init/exit common routine Remove the duplicated code and use the cpuidle common code for initialization. Signed-off-by: Daniel Lezcano Acked-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 20785b2..cca045c 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "powerdomain.h" #include "clockdomain.h" @@ -259,8 +260,6 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, return ret; } -static DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev); - static struct cpuidle_driver omap3_idle_driver = { .name = "omap3_idle", .owner = THIS_MODULE, @@ -336,8 +335,6 @@ static struct cpuidle_driver omap3_idle_driver = { */ int __init omap3_idle_init(void) { - struct cpuidle_device *dev; - mpu_pd = pwrdm_lookup("mpu_pwrdm"); core_pd = pwrdm_lookup("core_pwrdm"); per_pd = pwrdm_lookup("per_pwrdm"); @@ -346,20 +343,5 @@ int __init omap3_idle_init(void) if (!mpu_pd || !core_pd || !per_pd || !cam_pd) return -ENODEV; - if (cpuidle_register_driver(&omap3_idle_driver)) { - pr_err("%s: CPUidle driver register failed\n", __func__); - return -EIO; - } - - dev = &per_cpu(omap3_idle_dev, smp_processor_id()); - dev->cpu = 0; - - if (cpuidle_register_device(dev)) { - printk(KERN_ERR "%s: CPUidle register device failed\n", - __func__); - cpuidle_unregister_driver(&omap3_idle_driver); - return -EIO; - } - - return 0; + return cpuidle_register(&omap3_idle_driver, NULL); } -- cgit v0.10.2 From e158f9da6974cc11bfab2246a9b10021af0e0d8a Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 23 Apr 2013 08:54:37 +0000 Subject: ARM: tegra: cpuidle: use init/exit common routine Remove the duplicated code and use the cpuidle common code for initialization. Signed-off-by: Daniel Lezcano Acked-by: Stephen Warren Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c index c5fadf9..1d1c602 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra114.c +++ b/arch/arm/mach-tegra/cpuidle-tegra114.c @@ -29,31 +29,7 @@ static struct cpuidle_driver tegra_idle_driver = { }, }; -static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device); - int __init tegra114_cpuidle_init(void) { - int ret; - unsigned int cpu; - struct cpuidle_device *dev; - struct cpuidle_driver *drv = &tegra_idle_driver; - - ret = cpuidle_register_driver(&tegra_idle_driver); - if (ret) { - pr_err("CPUidle driver registration failed\n"); - return ret; - } - - for_each_possible_cpu(cpu) { - dev = &per_cpu(tegra_idle_device, cpu); - dev->cpu = cpu; - - ret = cpuidle_register_device(dev); - if (ret) { - pr_err("CPU%u: CPUidle device registration failed\n", - cpu); - return ret; - } - } - return 0; + return cpuidle_register(&tegra_idle_driver, NULL); } -- cgit v0.10.2 From 3cf4bc36f534550cfd4b0902e1a0408aded33a66 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 23 Apr 2013 08:54:38 +0000 Subject: ARM: shmobile: cpuidle: use init/exit common routine Remove the duplicated code and use the cpuidle common code for initialization. Signed-off-by: Daniel Lezcano Acked-by: Simon Horman Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-shmobile/cpuidle.c b/arch/arm/mach-shmobile/cpuidle.c index d671ae9..0afeb5c 100644 --- a/arch/arm/mach-shmobile/cpuidle.c +++ b/arch/arm/mach-shmobile/cpuidle.c @@ -16,7 +16,6 @@ #include #include -static struct cpuidle_device shmobile_cpuidle_dev; static struct cpuidle_driver shmobile_cpuidle_default_driver = { .name = "shmobile_cpuidle", .owner = THIS_MODULE, @@ -34,12 +33,5 @@ void __init shmobile_cpuidle_set_driver(struct cpuidle_driver *drv) int __init shmobile_cpuidle_init(void) { - struct cpuidle_device *dev = &shmobile_cpuidle_dev; - - cpuidle_register_driver(cpuidle_drv); - - dev->state_count = cpuidle_drv->state_count; - cpuidle_register_device(dev); - - return 0; + return cpuidle_register(cpuidle_drv, NULL); } -- cgit v0.10.2 From 0e9e8b4b918a7d2fc622bc93ee77e82ecae37d40 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 23 Apr 2013 08:54:39 +0000 Subject: ARM: OMAP4: cpuidle: use init/exit common routine Remove the duplicated code and use the cpuidle common code for initialization. Signed-off-by: Daniel Lezcano Acked-by: Santosh Shilimkar Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index d1bfb21..5a286b5 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -15,6 +15,7 @@ #include #include +#include #include #include "common.h" @@ -159,8 +160,6 @@ fail: return index; } -static DEFINE_PER_CPU(struct cpuidle_device, omap_idle_dev); - static struct cpuidle_driver omap4_idle_driver = { .name = "omap4_idle", .owner = THIS_MODULE, @@ -209,9 +208,6 @@ static struct cpuidle_driver omap4_idle_driver = { */ int __init omap4_idle_init(void) { - struct cpuidle_device *dev; - unsigned int cpu_id = 0; - mpu_pd = pwrdm_lookup("mpu_pwrdm"); cpu_pd[0] = pwrdm_lookup("cpu0_pwrdm"); cpu_pd[1] = pwrdm_lookup("cpu1_pwrdm"); @@ -223,23 +219,5 @@ int __init omap4_idle_init(void) if (!cpu_clkdm[0] || !cpu_clkdm[1]) return -ENODEV; - if (cpuidle_register_driver(&omap4_idle_driver)) { - pr_err("%s: CPUidle driver register failed\n", __func__); - return -EIO; - } - - for_each_cpu(cpu_id, cpu_online_mask) { - dev = &per_cpu(omap_idle_dev, cpu_id); - dev->cpu = cpu_id; -#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED - dev->coupled_cpus = *cpu_online_mask; -#endif - if (cpuidle_register_device(dev)) { - pr_err("%s: CPUidle register failed\n", __func__); - cpuidle_unregister_driver(&omap4_idle_driver); - return -EIO; - } - } - - return 0; + return cpuidle_register(&omap4_idle_driver, cpu_online_mask); } -- cgit v0.10.2 From c5106c9dea9a6022ab84c6cb1d4a0b19fc5af0e2 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 23 Apr 2013 08:54:40 +0000 Subject: ARM: tegra: cpuidle: use init/exit common routine for tegra2 Remove the duplicated code and use the cpuidle common code for initialization. Signed-off-by: Daniel Lezcano Acked-by: Stephen Warren Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c index f1f6ac4..590ec25 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra20.c +++ b/arch/arm/mach-tegra/cpuidle-tegra20.c @@ -70,8 +70,6 @@ static struct cpuidle_driver tegra_idle_driver = { .safe_state_index = 0, }; -static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device); - #ifdef CONFIG_PM_SLEEP #ifdef CONFIG_SMP static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); @@ -220,34 +218,8 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev, int __init tegra20_cpuidle_init(void) { - int ret; - unsigned int cpu; - struct cpuidle_device *dev; - struct cpuidle_driver *drv = &tegra_idle_driver; - #ifdef CONFIG_PM_SLEEP tegra_tear_down_cpu = tegra20_tear_down_cpu; #endif - - ret = cpuidle_register_driver(&tegra_idle_driver); - if (ret) { - pr_err("CPUidle driver registration failed\n"); - return ret; - } - - for_each_possible_cpu(cpu) { - dev = &per_cpu(tegra_idle_device, cpu); - dev->cpu = cpu; -#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED - dev->coupled_cpus = *cpu_possible_mask; -#endif - - ret = cpuidle_register_device(dev); - if (ret) { - pr_err("CPU%u: CPUidle device registration failed\n", - cpu); - return ret; - } - } - return 0; + return cpuidle_register(&tegra_idle_driver, cpu_possible_mask); } -- cgit v0.10.2 From f040c26ffaa5e56f2bca427c719c9601a02e70e5 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 23 Apr 2013 08:54:41 +0000 Subject: ARM: tegra: cpuidle: use init/exit common routine for tegra3 Remove the duplicated code and use the cpuidle common code for initialization. Signed-off-by: Daniel Lezcano Acked-by: Stephen Warren Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c index f6a0c72..36dc2be 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra30.c +++ b/arch/arm/mach-tegra/cpuidle-tegra30.c @@ -64,8 +64,6 @@ static struct cpuidle_driver tegra_idle_driver = { }, }; -static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device); - #ifdef CONFIG_PM_SLEEP static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev, struct cpuidle_driver *drv, @@ -156,31 +154,8 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev, int __init tegra30_cpuidle_init(void) { - int ret; - unsigned int cpu; - struct cpuidle_device *dev; - struct cpuidle_driver *drv = &tegra_idle_driver; - #ifdef CONFIG_PM_SLEEP tegra_tear_down_cpu = tegra30_tear_down_cpu; #endif - - ret = cpuidle_register_driver(&tegra_idle_driver); - if (ret) { - pr_err("CPUidle driver registration failed\n"); - return ret; - } - - for_each_possible_cpu(cpu) { - dev = &per_cpu(tegra_idle_device, cpu); - dev->cpu = cpu; - - ret = cpuidle_register_device(dev); - if (ret) { - pr_err("CPU%u: CPUidle device registration failed\n", - cpu); - return ret; - } - } - return 0; + return cpuidle_register(&tegra_idle_driver, NULL); } -- cgit v0.10.2 From 0b210d96a6f9f8fc10bca482ca6f6d87bf52927e Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 23 Apr 2013 08:54:42 +0000 Subject: ARM: calxeda: cpuidle: use init/exit common routine Remove the duplicated code and use the cpuidle common code for initialization. Signed-off-by: Daniel Lezcano Acked-by: Rob Herring Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/cpuidle-calxeda.c b/drivers/cpuidle/cpuidle-calxeda.c index a3b56f5..e344b56 100644 --- a/drivers/cpuidle/cpuidle-calxeda.c +++ b/drivers/cpuidle/cpuidle-calxeda.c @@ -35,8 +35,6 @@ extern void highbank_set_cpu_jump(int cpu, void *jump_addr); extern void *scu_base_addr; -static struct cpuidle_device __percpu *calxeda_idle_cpuidle_devices; - static inline unsigned int get_auxcr(void) { unsigned int val; @@ -85,19 +83,6 @@ static int calxeda_pwrdown_idle(struct cpuidle_device *dev, return index; } -static void calxeda_idle_cpuidle_devices_uninit(void) -{ - int i; - struct cpuidle_device *dev; - - for_each_possible_cpu(i) { - dev = per_cpu_ptr(calxeda_idle_cpuidle_devices, i); - cpuidle_unregister_device(dev); - } - - free_percpu(calxeda_idle_cpuidle_devices); -} - static struct cpuidle_driver calxeda_idle_driver = { .name = "calxeda_idle", .states = { @@ -117,44 +102,9 @@ static struct cpuidle_driver calxeda_idle_driver = { static int __init calxeda_cpuidle_init(void) { - int cpu_id; - int ret; - struct cpuidle_device *dev; - struct cpuidle_driver *drv = &calxeda_idle_driver; - if (!of_machine_is_compatible("calxeda,highbank")) return -ENODEV; - ret = cpuidle_register_driver(drv); - if (ret) - return ret; - - calxeda_idle_cpuidle_devices = alloc_percpu(struct cpuidle_device); - if (calxeda_idle_cpuidle_devices == NULL) { - ret = -ENOMEM; - goto unregister_drv; - } - - /* initialize state data for each cpuidle_device */ - for_each_possible_cpu(cpu_id) { - dev = per_cpu_ptr(calxeda_idle_cpuidle_devices, cpu_id); - dev->cpu = cpu_id; - dev->state_count = drv->state_count; - - ret = cpuidle_register_device(dev); - if (ret) { - pr_err("Failed to register cpu %u, error: %d\n", - cpu_id, ret); - goto uninit; - } - } - - return 0; - -uninit: - calxeda_idle_cpuidle_devices_uninit(); -unregister_drv: - cpuidle_unregister_driver(drv); - return ret; + return cpuidle_register(&calxeda_idle_driver, NULL); } module_init(calxeda_cpuidle_init); -- cgit v0.10.2 From 30dc72c6fa91c640e98ce5ef5ec33fb2beb41ad2 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 23 Apr 2013 08:54:43 +0000 Subject: ARM: kirkwood: cpuidle: use init/exit common routine Remove the duplicated code and use the cpuidle common code for initialization. Signed-off-by: Daniel Lezcano Tested-by: Andrew Lunn Acked-by: Andrew Lunn Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/cpuidle-kirkwood.c b/drivers/cpuidle/cpuidle-kirkwood.c index 6f31524..53290e1 100644 --- a/drivers/cpuidle/cpuidle-kirkwood.c +++ b/drivers/cpuidle/cpuidle-kirkwood.c @@ -52,9 +52,6 @@ static struct cpuidle_driver kirkwood_idle_driver = { }, .state_count = KIRKWOOD_MAX_STATES, }; -static struct cpuidle_device *device; - -static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device); /* Initialize CPU idle by registering the idle states */ static int kirkwood_cpuidle_probe(struct platform_device *pdev) @@ -69,22 +66,12 @@ static int kirkwood_cpuidle_probe(struct platform_device *pdev) if (IS_ERR(ddr_operation_base)) return PTR_ERR(ddr_operation_base); - device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id()); - device->state_count = KIRKWOOD_MAX_STATES; - - cpuidle_register_driver(&kirkwood_idle_driver); - if (cpuidle_register_device(device)) { - pr_err("kirkwood_init_cpuidle: Failed registering\n"); - return -EIO; - } - return 0; + return cpuidle_register(&kirkwood_idle_driver, NULL); } int kirkwood_cpuidle_remove(struct platform_device *pdev) { - cpuidle_unregister_device(device); - cpuidle_unregister_driver(&kirkwood_idle_driver); - + cpuidle_unregister(&kirkwood_idle_driver); return 0; } -- cgit v0.10.2 From 3aec034590d98cb268b3a1f434a602b3d53b0ad2 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 23 Apr 2013 08:54:44 +0000 Subject: ARM: davinci: cpuidle: use init/exit common routine Remove the duplicated code and use the cpuidle common code for initialization. Signed-off-by: Daniel Lezcano Acked-by: Sekhar Nori Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c index c2887c5..36aef3a 100644 --- a/arch/arm/mach-davinci/cpuidle.c +++ b/arch/arm/mach-davinci/cpuidle.c @@ -25,7 +25,6 @@ #define DAVINCI_CPUIDLE_MAX_STATES 2 -static DEFINE_PER_CPU(struct cpuidle_device, davinci_cpuidle_device); static void __iomem *ddr2_reg_base; static bool ddr2_pdown; @@ -76,12 +75,8 @@ static struct cpuidle_driver davinci_idle_driver = { static int __init davinci_cpuidle_probe(struct platform_device *pdev) { - int ret; - struct cpuidle_device *device; struct davinci_cpuidle_config *pdata = pdev->dev.platform_data; - device = &per_cpu(davinci_cpuidle_device, smp_processor_id()); - if (!pdata) { dev_err(&pdev->dev, "cannot get platform data\n"); return -ENOENT; @@ -91,20 +86,7 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev) ddr2_pdown = pdata->ddr2_pdown; - ret = cpuidle_register_driver(&davinci_idle_driver); - if (ret) { - dev_err(&pdev->dev, "failed to register driver\n"); - return ret; - } - - ret = cpuidle_register_device(device); - if (ret) { - dev_err(&pdev->dev, "failed to register device\n"); - cpuidle_unregister_driver(&davinci_idle_driver); - return ret; - } - - return 0; + return cpuidle_register(&davinci_idle_driver, NULL); } static struct platform_driver davinci_cpuidle_driver = { -- cgit v0.10.2 From 54a4644b7a31b017375018d8266a22d3eabfcf0e Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 23 Apr 2013 08:54:45 +0000 Subject: ARM: imx: cpuidle: use init/exit common routine The code intializes the cpuidle driver at different places. The cpuidle driver for : * imx5 : is in the pm-imx5.c, the init function is in cpuidle.c * imx6 : is in cpuidle-imx6q.c, the init function is in cpuidle.c and cpuidle-imx6q.c Instead of having the cpuidle code spread across different files, let's create a driver for each SoC and use the common register function. Signed-off-by: Daniel Lezcano Acked-by: Shawn Guo Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index c4ce090..cb70961 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -30,7 +30,7 @@ obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o ifeq ($(CONFIG_CPU_IDLE),y) -obj-y += cpuidle.o +obj-$(CONFIG_SOC_IMX5) += cpuidle-imx5.o obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o endif diff --git a/arch/arm/mach-imx/cpuidle-imx5.c b/arch/arm/mach-imx/cpuidle-imx5.c new file mode 100644 index 0000000..5a47e3c --- /dev/null +++ b/arch/arm/mach-imx/cpuidle-imx5.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +static int imx5_cpuidle_enter(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + arm_pm_idle(); + return index; +} + +static struct cpuidle_driver imx5_cpuidle_driver = { + .name = "imx5_cpuidle", + .owner = THIS_MODULE, + .states[0] = { + .enter = imx5_cpuidle_enter, + .exit_latency = 2, + .target_residency = 1, + .flags = CPUIDLE_FLAG_TIME_VALID, + .name = "IMX5 SRPG", + .desc = "CPU state retained,powered off", + }, + .state_count = 1, +}; + +int __init imx5_cpuidle_init(void) +{ + return cpuidle_register(&imx5_cpuidle_driver, NULL); +} diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c index e2739ad..23ddfb6 100644 --- a/arch/arm/mach-imx/cpuidle-imx6q.c +++ b/arch/arm/mach-imx/cpuidle-imx6q.c @@ -71,5 +71,5 @@ int __init imx6q_cpuidle_init(void) /* Set chicken bit to get a reliable WAIT mode support */ imx6q_set_chicken_bit(); - return imx_cpuidle_init(&imx6q_cpuidle_driver); + return cpuidle_register(&imx6q_cpuidle_driver, NULL); } diff --git a/arch/arm/mach-imx/cpuidle.c b/arch/arm/mach-imx/cpuidle.c deleted file mode 100644 index d4cb511..0000000 --- a/arch/arm/mach-imx/cpuidle.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2012 Freescale Semiconductor, Inc. - * 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 -#include -#include -#include -#include -#include - -static struct cpuidle_device __percpu * imx_cpuidle_devices; - -static void __init imx_cpuidle_devices_uninit(void) -{ - int cpu_id; - struct cpuidle_device *dev; - - for_each_possible_cpu(cpu_id) { - dev = per_cpu_ptr(imx_cpuidle_devices, cpu_id); - cpuidle_unregister_device(dev); - } - - free_percpu(imx_cpuidle_devices); -} - -int __init imx_cpuidle_init(struct cpuidle_driver *drv) -{ - struct cpuidle_device *dev; - int cpu_id, ret; - - if (drv->state_count > CPUIDLE_STATE_MAX) { - pr_err("%s: state_count exceeds maximum\n", __func__); - return -EINVAL; - } - - ret = cpuidle_register_driver(drv); - if (ret) { - pr_err("%s: Failed to register cpuidle driver with error: %d\n", - __func__, ret); - return ret; - } - - imx_cpuidle_devices = alloc_percpu(struct cpuidle_device); - if (imx_cpuidle_devices == NULL) { - ret = -ENOMEM; - goto unregister_drv; - } - - /* initialize state data for each cpuidle_device */ - for_each_possible_cpu(cpu_id) { - dev = per_cpu_ptr(imx_cpuidle_devices, cpu_id); - dev->cpu = cpu_id; - dev->state_count = drv->state_count; - - ret = cpuidle_register_device(dev); - if (ret) { - pr_err("%s: Failed to register cpu %u, error: %d\n", - __func__, cpu_id, ret); - goto uninit; - } - } - - return 0; - -uninit: - imx_cpuidle_devices_uninit(); - -unregister_drv: - cpuidle_unregister_driver(drv); - return ret; -} diff --git a/arch/arm/mach-imx/cpuidle.h b/arch/arm/mach-imx/cpuidle.h index e092d13..786f98e 100644 --- a/arch/arm/mach-imx/cpuidle.h +++ b/arch/arm/mach-imx/cpuidle.h @@ -10,18 +10,16 @@ * http://www.gnu.org/copyleft/gpl.html */ -#include - #ifdef CONFIG_CPU_IDLE -extern int imx_cpuidle_init(struct cpuidle_driver *drv); +extern int imx5_cpuidle_init(void); extern int imx6q_cpuidle_init(void); #else -static inline int imx_cpuidle_init(struct cpuidle_driver *drv) +static inline int imx5_cpuidle_init(void) { - return -ENODEV; + return 0; } static inline int imx6q_cpuidle_init(void) { - return -ENODEV; + return 0; } #endif diff --git a/arch/arm/mach-imx/pm-imx5.c b/arch/arm/mach-imx/pm-imx5.c index 4b52b3e..82e79c6 100644 --- a/arch/arm/mach-imx/pm-imx5.c +++ b/arch/arm/mach-imx/pm-imx5.c @@ -149,32 +149,6 @@ static void imx5_pm_idle(void) imx5_cpu_do_idle(); } -static int imx5_cpuidle_enter(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int idx) -{ - int ret; - - ret = imx5_cpu_do_idle(); - if (ret < 0) - return ret; - - return idx; -} - -static struct cpuidle_driver imx5_cpuidle_driver = { - .name = "imx5_cpuidle", - .owner = THIS_MODULE, - .states[0] = { - .enter = imx5_cpuidle_enter, - .exit_latency = 2, - .target_residency = 1, - .flags = CPUIDLE_FLAG_TIME_VALID, - .name = "IMX5 SRPG", - .desc = "CPU state retained,powered off", - }, - .state_count = 1, -}; - static int __init imx5_pm_common_init(void) { int ret; @@ -192,8 +166,7 @@ static int __init imx5_pm_common_init(void) /* Set the registers to the default cpu idle state. */ mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE); - imx_cpuidle_init(&imx5_cpuidle_driver); - return 0; + return imx5_cpuidle_init(); } void __init imx51_pm_init(void) -- cgit v0.10.2 From 1c192d047a0ddc8e25a8b8f43c80c93330bdf929 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 23 Apr 2013 15:28:44 +0000 Subject: cpuidle: fix comment format Fix comment format for the kernel doc script. Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 49e8d30..c3a93fe 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -454,7 +454,7 @@ void cpuidle_unregister_device(struct cpuidle_device *dev) EXPORT_SYMBOL_GPL(cpuidle_unregister_device); -/* +/** * 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. -- cgit v0.10.2 From b181a3b03f866776211f22390c185c4da1dc45ff Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 23 Apr 2013 14:41:17 +0000 Subject: SH: cpuidle: use init/exit common routine Remove the duplicated code and use the cpuidle common code for initialization. Signed-off-by: Daniel Lezcano Acked-by: Simon Horman Signed-off-by: Rafael J. Wysocki diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c index fdfe57f4..d306225 100644 --- a/arch/sh/kernel/cpu/shmobile/cpuidle.c +++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c @@ -51,7 +51,6 @@ static int cpuidle_sleep_enter(struct cpuidle_device *dev, return k; } -static struct cpuidle_device cpuidle_dev; static struct cpuidle_driver cpuidle_driver = { .name = "sh_idle", .owner = THIS_MODULE, @@ -100,9 +99,5 @@ int __init sh_mobile_setup_cpuidle(void) if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) cpuidle_driver.states[2].disabled = false; - ret = cpuidle_register_driver(&cpuidle_driver); - if (ret) - return ret; - - return cpuidle_register_device(&cpuidle_dev); + return cpuidle_register(&cpuidle_driver); } -- cgit v0.10.2 From 9fe3d35a32a9be259435e30fdca680cb78bd6d6f Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 23 Apr 2013 14:41:16 +0000 Subject: ARM: s3c64xx: cpuidle: use init/exit common routine Remove the duplicated code and use the cpuidle common code for initialization. Signed-off-by: Daniel Lezcano Acked-by: Kukjin Kim Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-s3c64xx/cpuidle.c b/arch/arm/mach-s3c64xx/cpuidle.c index 852ff16..3c8ab07 100644 --- a/arch/arm/mach-s3c64xx/cpuidle.c +++ b/arch/arm/mach-s3c64xx/cpuidle.c @@ -40,8 +40,6 @@ static int s3c64xx_enter_idle(struct cpuidle_device *dev, return index; } -static DEFINE_PER_CPU(struct cpuidle_device, s3c64xx_cpuidle_device); - static struct cpuidle_driver s3c64xx_cpuidle_driver = { .name = "s3c64xx_cpuidle", .owner = THIS_MODULE, @@ -60,16 +58,6 @@ static struct cpuidle_driver s3c64xx_cpuidle_driver = { static int __init s3c64xx_init_cpuidle(void) { - int ret; - - cpuidle_register_driver(&s3c64xx_cpuidle_driver); - - ret = cpuidle_register_device(&s3c64xx_cpuidle_device); - if (ret) { - pr_err("Failed to register cpuidle device: %d\n", ret); - return ret; - } - - return 0; + return cpuidle_register(&s3c64xx_cpuidle_driver, NULL); } device_initcall(s3c64xx_init_cpuidle); -- cgit v0.10.2 From a8e39c35b5d09598e129aa9b5e6f35aa3a1915d9 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 26 Apr 2013 11:05:44 +0000 Subject: cpuidle: add maintainer entry Currently cpuidle drivers are spread across different archs. As a result, there are several different paths for cpuidle patch submissions: cpuidle core changes go through linux-pm, ARM driver changes go to the arm-soc or SoC-specific trees, sh changes go through the sh arch tree, pseries changes go through the PowerPC tree and finally intel changes go through the Len's tree while ACPI idle changes go through linux-pm. That makes it difficult to consolidate code and to propagate modifications from the cpuidle core to the different drivers. Hopefully, a movement has started to put the majority of cpuidle drivers under drivers/cpuidle like cpuidle-calxeda.c and cpuidle-kirkwood.c. Add a maintainer entry for cpuidle to MAINTAINERS to clarify the situation and to indicate to new cpuidle driver authors that those drivers should not go into arch-specific directories. The upstreaming process is unchanged: Rafael takes patches for merging into his tree, but with an Acked-by: tag from the driver's maintainer, so indicate in the drivers' headers who maintains them. The arrangement will be the same as for cpufreq. [rjw: Changelog] Signed-off-by: Daniel Lezcano Acked-by: Linus Walleij Acked-by: Andrew Lunn #for kirkwood Acked-by: Jason Cooper #for kirkwood Acked-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki diff --git a/MAINTAINERS b/MAINTAINERS index 836a618..2f20dc4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2206,6 +2206,15 @@ S: Maintained F: drivers/cpufreq/ F: include/linux/cpufreq.h +CPUIDLE DRIVERS +M: Rafael J. Wysocki +M: Daniel Lezcano +L: linux-pm@vger.kernel.org +S: Maintained +T: git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git +F: drivers/cpuidle/* +F: include/linux/cpuidle.h + CPUID/MSR DRIVER M: "H. Peter Anvin" S: Maintained diff --git a/drivers/cpuidle/cpuidle-calxeda.c b/drivers/cpuidle/cpuidle-calxeda.c index e344b56..2233791 100644 --- a/drivers/cpuidle/cpuidle-calxeda.c +++ b/drivers/cpuidle/cpuidle-calxeda.c @@ -1,7 +1,7 @@ /* * Copyright 2012 Calxeda, Inc. * - * Based on arch/arm/plat-mxc/cpuidle.c: + * Based on arch/arm/plat-mxc/cpuidle.c: #v3.7 * Copyright 2012 Freescale Semiconductor, Inc. * Copyright 2012 Linaro Ltd. * @@ -16,6 +16,8 @@ * * You should have received a copy of the GNU General Public License along with * this program. If not, see . + * + * Maintainer: Rob Herring */ #include diff --git a/drivers/cpuidle/cpuidle-kirkwood.c b/drivers/cpuidle/cpuidle-kirkwood.c index 53290e1..521b0a7 100644 --- a/drivers/cpuidle/cpuidle-kirkwood.c +++ b/drivers/cpuidle/cpuidle-kirkwood.c @@ -1,6 +1,4 @@ /* - * arch/arm/mach-kirkwood/cpuidle.c - * * CPU idle Marvell Kirkwood SoCs * * This file is licensed under the terms of the GNU General Public @@ -11,6 +9,9 @@ * to implement two idle states - * #1 wait-for-interrupt * #2 wait-for-interrupt and DDR self refresh + * + * Maintainer: Jason Cooper + * Maintainer: Andrew Lunn */ #include -- cgit v0.10.2