Merge branch 'pm-cpuidle-next' into linux-next

* pm-cpuidle-next:
  cpuidle: imx6: remove timer broadcast initialization
  cpuidle: OMAP4: remove timer broadcast initialization
  cpuidle: ux500: remove timer broadcast initialization
  cpuidle: initialize the broadcast timer framework
  timer: move enum definition out of ifdef section
  cpuidle: kirkwood: fix coccicheck warnings
  cpuidle / kirkwood: remove redundant Kconfig option
  cpuidle / ux500 : use CPUIDLE_FLAG_TIMER_STOP flag
  cpuidle / imx6 : use CPUIDLE_FLAG_TIMER_STOP flag
  cpuidle / omap4 : use CPUIDLE_FLAG_TIMER_STOP flag
  cpuidle : handle clockevent notify from the cpuidle framework
This commit is contained in:
Rafael J. Wysocki 2013-04-08 12:32:07 +02:00
commit f69e44b205
11 changed files with 69 additions and 94 deletions

View File

@ -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

View File

@ -6,7 +6,6 @@
* published by the Free Software Foundation.
*/
#include <linux/clockchips.h>
#include <linux/cpuidle.h>
#include <linux/module.h>
#include <asm/cpuidle.h>
@ -21,10 +20,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,22 +38,10 @@ idle:
cpu_do_idle();
done:
atomic_dec(&master);
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
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,
@ -70,7 +53,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",
@ -88,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);
}

View File

@ -14,7 +14,6 @@
#include <linux/cpuidle.h>
#include <linux/cpu_pm.h>
#include <linux/export.h>
#include <linux/clockchips.h>
#include <asm/proc-fns.h>
@ -82,7 +81,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 +107,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 +148,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;
@ -163,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 = {
@ -193,7 +177,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 +187,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",
@ -236,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;

View File

@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/cpuidle.h>
#include <linux/clockchips.h>
#include <linux/spinlock.h>
#include <linux/atomic.h>
#include <linux/smp.h>
@ -30,8 +29,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 +88,6 @@ out:
spin_unlock(&master_lock);
}
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &this_cpu);
return index;
}
@ -106,7 +101,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",
},
@ -115,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;
@ -134,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");

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -8,6 +8,7 @@
* This code is licenced under the GPL.
*/
#include <linux/clockchips.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/sched.h>
@ -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 */

View File

@ -11,6 +11,8 @@
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/cpuidle.h>
#include <linux/cpumask.h>
#include <linux/clockchips.h>
#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

View File

@ -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 <linux/clocksource.h>
@ -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

View File

@ -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)
@ -106,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;