diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-04-08 06:32:07 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-04-08 06:32:07 -0400 |
commit | f69e44b2059f2238ac558b4a115ebcdefe20b9be (patch) | |
tree | be2a95654d7c9cb38bbcbb7a83b862db359c79e1 | |
parent | 0f0c8aa0d0562954cdfa135efb827067de7ba855 (diff) | |
parent | b6269efb146eb8770d753e3dc1c561f1cffb631a (diff) |
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
-rw-r--r-- | arch/arm/configs/kirkwood_defconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-imx/cpuidle-imx6q.c | 23 | ||||
-rw-r--r-- | arch/arm/mach-omap2/cpuidle44xx.c | 25 | ||||
-rw-r--r-- | arch/arm/mach-ux500/cpuidle.c | 25 | ||||
-rw-r--r-- | drivers/cpuidle/Kconfig | 6 | ||||
-rw-r--r-- | drivers/cpuidle/Makefile | 2 | ||||
-rw-r--r-- | drivers/cpuidle/cpuidle-kirkwood.c | 6 | ||||
-rw-r--r-- | drivers/cpuidle/cpuidle.c | 9 | ||||
-rw-r--r-- | drivers/cpuidle/driver.c | 31 | ||||
-rw-r--r-- | include/linux/clockchips.h | 32 | ||||
-rw-r--r-- | include/linux/cpuidle.h | 3 |
11 files changed, 69 insertions, 94 deletions
diff --git a/arch/arm/configs/kirkwood_defconfig b/arch/arm/configs/kirkwood_defconfig index 13482ea58b09..93f3794ba5cb 100644 --- a/arch/arm/configs/kirkwood_defconfig +++ b/arch/arm/configs/kirkwood_defconfig | |||
@@ -56,7 +56,6 @@ CONFIG_AEABI=y | |||
56 | CONFIG_ZBOOT_ROM_TEXT=0x0 | 56 | CONFIG_ZBOOT_ROM_TEXT=0x0 |
57 | CONFIG_ZBOOT_ROM_BSS=0x0 | 57 | CONFIG_ZBOOT_ROM_BSS=0x0 |
58 | CONFIG_CPU_IDLE=y | 58 | CONFIG_CPU_IDLE=y |
59 | CONFIG_CPU_IDLE_KIRKWOOD=y | ||
60 | CONFIG_NET=y | 59 | CONFIG_NET=y |
61 | CONFIG_PACKET=y | 60 | CONFIG_PACKET=y |
62 | CONFIG_UNIX=y | 61 | CONFIG_UNIX=y |
diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c index d533e2695f0e..a783a6314b4f 100644 --- a/arch/arm/mach-imx/cpuidle-imx6q.c +++ b/arch/arm/mach-imx/cpuidle-imx6q.c | |||
@@ -6,7 +6,6 @@ | |||
6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/clockchips.h> | ||
10 | #include <linux/cpuidle.h> | 9 | #include <linux/cpuidle.h> |
11 | #include <linux/module.h> | 10 | #include <linux/module.h> |
12 | #include <asm/cpuidle.h> | 11 | #include <asm/cpuidle.h> |
@@ -21,10 +20,6 @@ static DEFINE_SPINLOCK(master_lock); | |||
21 | static int imx6q_enter_wait(struct cpuidle_device *dev, | 20 | static int imx6q_enter_wait(struct cpuidle_device *dev, |
22 | struct cpuidle_driver *drv, int index) | 21 | struct cpuidle_driver *drv, int index) |
23 | { | 22 | { |
24 | int cpu = dev->cpu; | ||
25 | |||
26 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); | ||
27 | |||
28 | if (atomic_inc_return(&master) == num_online_cpus()) { | 23 | if (atomic_inc_return(&master) == num_online_cpus()) { |
29 | /* | 24 | /* |
30 | * With this lock, we prevent other cpu to exit and enter | 25 | * With this lock, we prevent other cpu to exit and enter |
@@ -43,22 +38,10 @@ idle: | |||
43 | cpu_do_idle(); | 38 | cpu_do_idle(); |
44 | done: | 39 | done: |
45 | atomic_dec(&master); | 40 | atomic_dec(&master); |
46 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); | ||
47 | 41 | ||
48 | return index; | 42 | return index; |
49 | } | 43 | } |
50 | 44 | ||
51 | /* | ||
52 | * For each cpu, setup the broadcast timer because local timer | ||
53 | * stops for the states other than WFI. | ||
54 | */ | ||
55 | static void imx6q_setup_broadcast_timer(void *arg) | ||
56 | { | ||
57 | int cpu = smp_processor_id(); | ||
58 | |||
59 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu); | ||
60 | } | ||
61 | |||
62 | static struct cpuidle_driver imx6q_cpuidle_driver = { | 45 | static struct cpuidle_driver imx6q_cpuidle_driver = { |
63 | .name = "imx6q_cpuidle", | 46 | .name = "imx6q_cpuidle", |
64 | .owner = THIS_MODULE, | 47 | .owner = THIS_MODULE, |
@@ -70,7 +53,8 @@ static struct cpuidle_driver imx6q_cpuidle_driver = { | |||
70 | { | 53 | { |
71 | .exit_latency = 50, | 54 | .exit_latency = 50, |
72 | .target_residency = 75, | 55 | .target_residency = 75, |
73 | .flags = CPUIDLE_FLAG_TIME_VALID, | 56 | .flags = CPUIDLE_FLAG_TIME_VALID | |
57 | CPUIDLE_FLAG_TIMER_STOP, | ||
74 | .enter = imx6q_enter_wait, | 58 | .enter = imx6q_enter_wait, |
75 | .name = "WAIT", | 59 | .name = "WAIT", |
76 | .desc = "Clock off", | 60 | .desc = "Clock off", |
@@ -88,8 +72,5 @@ int __init imx6q_cpuidle_init(void) | |||
88 | /* Set chicken bit to get a reliable WAIT mode support */ | 72 | /* Set chicken bit to get a reliable WAIT mode support */ |
89 | imx6q_set_chicken_bit(); | 73 | imx6q_set_chicken_bit(); |
90 | 74 | ||
91 | /* Configure the broadcast timer on each cpu */ | ||
92 | on_each_cpu(imx6q_setup_broadcast_timer, NULL, 1); | ||
93 | |||
94 | return imx_cpuidle_init(&imx6q_cpuidle_driver); | 75 | return imx_cpuidle_init(&imx6q_cpuidle_driver); |
95 | } | 76 | } |
diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index d639aef0deda..f4b1b234939e 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c | |||
@@ -14,7 +14,6 @@ | |||
14 | #include <linux/cpuidle.h> | 14 | #include <linux/cpuidle.h> |
15 | #include <linux/cpu_pm.h> | 15 | #include <linux/cpu_pm.h> |
16 | #include <linux/export.h> | 16 | #include <linux/export.h> |
17 | #include <linux/clockchips.h> | ||
18 | 17 | ||
19 | #include <asm/proc-fns.h> | 18 | #include <asm/proc-fns.h> |
20 | 19 | ||
@@ -82,7 +81,6 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev, | |||
82 | int index) | 81 | int index) |
83 | { | 82 | { |
84 | struct omap4_idle_statedata *cx = &omap4_idle_data[index]; | 83 | struct omap4_idle_statedata *cx = &omap4_idle_data[index]; |
85 | int cpu_id = smp_processor_id(); | ||
86 | 84 | ||
87 | local_fiq_disable(); | 85 | local_fiq_disable(); |
88 | 86 | ||
@@ -109,8 +107,6 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev, | |||
109 | } | 107 | } |
110 | } | 108 | } |
111 | 109 | ||
112 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu_id); | ||
113 | |||
114 | /* | 110 | /* |
115 | * Call idle CPU PM enter notifier chain so that | 111 | * Call idle CPU PM enter notifier chain so that |
116 | * VFP and per CPU interrupt context is saved. | 112 | * VFP and per CPU interrupt context is saved. |
@@ -152,8 +148,6 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev, | |||
152 | if (omap4_mpuss_read_prev_context_state()) | 148 | if (omap4_mpuss_read_prev_context_state()) |
153 | cpu_cluster_pm_exit(); | 149 | cpu_cluster_pm_exit(); |
154 | 150 | ||
155 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu_id); | ||
156 | |||
157 | fail: | 151 | fail: |
158 | cpuidle_coupled_parallel_barrier(dev, &abort_barrier); | 152 | cpuidle_coupled_parallel_barrier(dev, &abort_barrier); |
159 | cpu_done[dev->cpu] = false; | 153 | cpu_done[dev->cpu] = false; |
@@ -163,16 +157,6 @@ fail: | |||
163 | return index; | 157 | return index; |
164 | } | 158 | } |
165 | 159 | ||
166 | /* | ||
167 | * For each cpu, setup the broadcast timer because local timers | ||
168 | * stops for the states above C1. | ||
169 | */ | ||
170 | static void omap_setup_broadcast_timer(void *arg) | ||
171 | { | ||
172 | int cpu = smp_processor_id(); | ||
173 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu); | ||
174 | } | ||
175 | |||
176 | static DEFINE_PER_CPU(struct cpuidle_device, omap4_idle_dev); | 160 | static DEFINE_PER_CPU(struct cpuidle_device, omap4_idle_dev); |
177 | 161 | ||
178 | static struct cpuidle_driver omap4_idle_driver = { | 162 | static struct cpuidle_driver omap4_idle_driver = { |
@@ -193,7 +177,8 @@ static struct cpuidle_driver omap4_idle_driver = { | |||
193 | /* C2 - CPU0 OFF + CPU1 OFF + MPU CSWR */ | 177 | /* C2 - CPU0 OFF + CPU1 OFF + MPU CSWR */ |
194 | .exit_latency = 328 + 440, | 178 | .exit_latency = 328 + 440, |
195 | .target_residency = 960, | 179 | .target_residency = 960, |
196 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED, | 180 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED | |
181 | CPUIDLE_FLAG_TIMER_STOP, | ||
197 | .enter = omap4_enter_idle_coupled, | 182 | .enter = omap4_enter_idle_coupled, |
198 | .name = "C2", | 183 | .name = "C2", |
199 | .desc = "MPUSS CSWR", | 184 | .desc = "MPUSS CSWR", |
@@ -202,7 +187,8 @@ static struct cpuidle_driver omap4_idle_driver = { | |||
202 | /* C3 - CPU0 OFF + CPU1 OFF + MPU OSWR */ | 187 | /* C3 - CPU0 OFF + CPU1 OFF + MPU OSWR */ |
203 | .exit_latency = 460 + 518, | 188 | .exit_latency = 460 + 518, |
204 | .target_residency = 1100, | 189 | .target_residency = 1100, |
205 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED, | 190 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED | |
191 | CPUIDLE_FLAG_TIMER_STOP, | ||
206 | .enter = omap4_enter_idle_coupled, | 192 | .enter = omap4_enter_idle_coupled, |
207 | .name = "C3", | 193 | .name = "C3", |
208 | .desc = "MPUSS OSWR", | 194 | .desc = "MPUSS OSWR", |
@@ -236,9 +222,6 @@ int __init omap4_idle_init(void) | |||
236 | if (!cpu_clkdm[0] || !cpu_clkdm[1]) | 222 | if (!cpu_clkdm[0] || !cpu_clkdm[1]) |
237 | return -ENODEV; | 223 | return -ENODEV; |
238 | 224 | ||
239 | /* Configure the broadcast timer on each cpu */ | ||
240 | on_each_cpu(omap_setup_broadcast_timer, NULL, 1); | ||
241 | |||
242 | for_each_cpu(cpu_id, cpu_online_mask) { | 225 | for_each_cpu(cpu_id, cpu_online_mask) { |
243 | dev = &per_cpu(omap4_idle_dev, cpu_id); | 226 | dev = &per_cpu(omap4_idle_dev, cpu_id); |
244 | dev->cpu = cpu_id; | 227 | dev->cpu = cpu_id; |
diff --git a/arch/arm/mach-ux500/cpuidle.c b/arch/arm/mach-ux500/cpuidle.c index ce9149302cc3..1b16d9ebecda 100644 --- a/arch/arm/mach-ux500/cpuidle.c +++ b/arch/arm/mach-ux500/cpuidle.c | |||
@@ -11,7 +11,6 @@ | |||
11 | 11 | ||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/cpuidle.h> | 13 | #include <linux/cpuidle.h> |
14 | #include <linux/clockchips.h> | ||
15 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
16 | #include <linux/atomic.h> | 15 | #include <linux/atomic.h> |
17 | #include <linux/smp.h> | 16 | #include <linux/smp.h> |
@@ -30,8 +29,6 @@ static inline int ux500_enter_idle(struct cpuidle_device *dev, | |||
30 | int this_cpu = smp_processor_id(); | 29 | int this_cpu = smp_processor_id(); |
31 | bool recouple = false; | 30 | bool recouple = false; |
32 | 31 | ||
33 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &this_cpu); | ||
34 | |||
35 | if (atomic_inc_return(&master) == num_online_cpus()) { | 32 | if (atomic_inc_return(&master) == num_online_cpus()) { |
36 | 33 | ||
37 | /* With this lock, we prevent the other cpu to exit and enter | 34 | /* With this lock, we prevent the other cpu to exit and enter |
@@ -91,8 +88,6 @@ out: | |||
91 | spin_unlock(&master_lock); | 88 | spin_unlock(&master_lock); |
92 | } | 89 | } |
93 | 90 | ||
94 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &this_cpu); | ||
95 | |||
96 | return index; | 91 | return index; |
97 | } | 92 | } |
98 | 93 | ||
@@ -106,7 +101,8 @@ static struct cpuidle_driver ux500_idle_driver = { | |||
106 | .enter = ux500_enter_idle, | 101 | .enter = ux500_enter_idle, |
107 | .exit_latency = 70, | 102 | .exit_latency = 70, |
108 | .target_residency = 260, | 103 | .target_residency = 260, |
109 | .flags = CPUIDLE_FLAG_TIME_VALID, | 104 | .flags = CPUIDLE_FLAG_TIME_VALID | |
105 | CPUIDLE_FLAG_TIMER_STOP, | ||
110 | .name = "ApIdle", | 106 | .name = "ApIdle", |
111 | .desc = "ARM Retention", | 107 | .desc = "ARM Retention", |
112 | }, | 108 | }, |
@@ -115,16 +111,6 @@ static struct cpuidle_driver ux500_idle_driver = { | |||
115 | .state_count = 2, | 111 | .state_count = 2, |
116 | }; | 112 | }; |
117 | 113 | ||
118 | /* | ||
119 | * For each cpu, setup the broadcast timer because we will | ||
120 | * need to migrate the timers for the states >= ApIdle. | ||
121 | */ | ||
122 | static void ux500_setup_broadcast_timer(void *arg) | ||
123 | { | ||
124 | int cpu = smp_processor_id(); | ||
125 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu); | ||
126 | } | ||
127 | |||
128 | int __init ux500_idle_init(void) | 114 | int __init ux500_idle_init(void) |
129 | { | 115 | { |
130 | int ret, cpu; | 116 | int ret, cpu; |
@@ -134,13 +120,6 @@ int __init ux500_idle_init(void) | |||
134 | prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) | | 120 | prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) | |
135 | PRCMU_WAKEUP(ABB)); | 121 | PRCMU_WAKEUP(ABB)); |
136 | 122 | ||
137 | /* | ||
138 | * Configure the timer broadcast for each cpu, that must | ||
139 | * be done from the cpu context, so we use a smp cross | ||
140 | * call with 'on_each_cpu'. | ||
141 | */ | ||
142 | on_each_cpu(ux500_setup_broadcast_timer, NULL, 1); | ||
143 | |||
144 | ret = cpuidle_register_driver(&ux500_idle_driver); | 123 | ret = cpuidle_register_driver(&ux500_idle_driver); |
145 | if (ret) { | 124 | if (ret) { |
146 | printk(KERN_ERR "failed to register ux500 idle driver\n"); | 125 | printk(KERN_ERR "failed to register ux500 idle driver\n"); |
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index 071e2c3eec4f..c4cc27e5c8a5 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig | |||
@@ -39,10 +39,4 @@ config CPU_IDLE_CALXEDA | |||
39 | help | 39 | help |
40 | Select this to enable cpuidle on Calxeda processors. | 40 | Select this to enable cpuidle on Calxeda processors. |
41 | 41 | ||
42 | config CPU_IDLE_KIRKWOOD | ||
43 | bool "CPU Idle Driver for Kirkwood processors" | ||
44 | depends on ARCH_KIRKWOOD | ||
45 | help | ||
46 | Select this to enable cpuidle on Kirkwood processors. | ||
47 | |||
48 | endif | 42 | endif |
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile index 24c6e7d945ed..0d8bd55e776f 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile | |||
@@ -6,4 +6,4 @@ obj-y += cpuidle.o driver.o governor.o sysfs.o governors/ | |||
6 | obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o | 6 | obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o |
7 | 7 | ||
8 | obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o | 8 | obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o |
9 | obj-$(CONFIG_CPU_IDLE_KIRKWOOD) += cpuidle-kirkwood.o | 9 | obj-$(CONFIG_ARCH_KIRKWOOD) += cpuidle-kirkwood.o |
diff --git a/drivers/cpuidle/cpuidle-kirkwood.c b/drivers/cpuidle/cpuidle-kirkwood.c index 670aa1e55cd6..53aad7324965 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) | |||
66 | if (res == NULL) | 66 | if (res == NULL) |
67 | return -EINVAL; | 67 | return -EINVAL; |
68 | 68 | ||
69 | ddr_operation_base = devm_request_and_ioremap(&pdev->dev, res); | 69 | ddr_operation_base = devm_ioremap_resource(&pdev->dev, res); |
70 | if (!ddr_operation_base) | 70 | if (IS_ERR(ddr_operation_base)) |
71 | return -EADDRNOTAVAIL; | 71 | return PTR_ERR(ddr_operation_base); |
72 | 72 | ||
73 | device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id()); | 73 | device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id()); |
74 | device->state_count = KIRKWOOD_MAX_STATES; | 74 | device->state_count = KIRKWOOD_MAX_STATES; |
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index eba69290e074..c50037029184 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * This code is licenced under the GPL. | 8 | * This code is licenced under the GPL. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/clockchips.h> | ||
11 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
12 | #include <linux/mutex.h> | 13 | #include <linux/mutex.h> |
13 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
@@ -146,12 +147,20 @@ int cpuidle_idle_call(void) | |||
146 | 147 | ||
147 | trace_cpu_idle_rcuidle(next_state, dev->cpu); | 148 | trace_cpu_idle_rcuidle(next_state, dev->cpu); |
148 | 149 | ||
150 | if (drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP) | ||
151 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, | ||
152 | &dev->cpu); | ||
153 | |||
149 | if (cpuidle_state_is_coupled(dev, drv, next_state)) | 154 | if (cpuidle_state_is_coupled(dev, drv, next_state)) |
150 | entered_state = cpuidle_enter_state_coupled(dev, drv, | 155 | entered_state = cpuidle_enter_state_coupled(dev, drv, |
151 | next_state); | 156 | next_state); |
152 | else | 157 | else |
153 | entered_state = cpuidle_enter_state(dev, drv, next_state); | 158 | entered_state = cpuidle_enter_state(dev, drv, next_state); |
154 | 159 | ||
160 | if (drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP) | ||
161 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, | ||
162 | &dev->cpu); | ||
163 | |||
155 | trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); | 164 | trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); |
156 | 165 | ||
157 | /* give the governor an opportunity to reflect on the outcome */ | 166 | /* give the governor an opportunity to reflect on the outcome */ |
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index 422c7b69ba7c..8dfaaae94444 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c | |||
@@ -11,6 +11,8 @@ | |||
11 | #include <linux/mutex.h> | 11 | #include <linux/mutex.h> |
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/cpuidle.h> | 13 | #include <linux/cpuidle.h> |
14 | #include <linux/cpumask.h> | ||
15 | #include <linux/clockchips.h> | ||
14 | 16 | ||
15 | #include "cpuidle.h" | 17 | #include "cpuidle.h" |
16 | 18 | ||
@@ -19,9 +21,28 @@ DEFINE_SPINLOCK(cpuidle_driver_lock); | |||
19 | static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu); | 21 | static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu); |
20 | static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu); | 22 | static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu); |
21 | 23 | ||
22 | static void __cpuidle_driver_init(struct cpuidle_driver *drv) | 24 | static void cpuidle_setup_broadcast_timer(void *arg) |
23 | { | 25 | { |
26 | int cpu = smp_processor_id(); | ||
27 | clockevents_notify((long)(arg), &cpu); | ||
28 | } | ||
29 | |||
30 | static void __cpuidle_driver_init(struct cpuidle_driver *drv, int cpu) | ||
31 | { | ||
32 | int i; | ||
33 | |||
24 | drv->refcnt = 0; | 34 | drv->refcnt = 0; |
35 | |||
36 | for (i = drv->state_count - 1; i >= 0 ; i--) { | ||
37 | |||
38 | if (!(drv->states[i].flags & CPUIDLE_FLAG_TIMER_STOP)) | ||
39 | continue; | ||
40 | |||
41 | drv->bctimer = 1; | ||
42 | on_each_cpu_mask(get_cpu_mask(cpu), cpuidle_setup_broadcast_timer, | ||
43 | (void *)CLOCK_EVT_NOTIFY_BROADCAST_ON, 1); | ||
44 | break; | ||
45 | } | ||
25 | } | 46 | } |
26 | 47 | ||
27 | static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu) | 48 | 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) | |||
35 | if (__cpuidle_get_cpu_driver(cpu)) | 56 | if (__cpuidle_get_cpu_driver(cpu)) |
36 | return -EBUSY; | 57 | return -EBUSY; |
37 | 58 | ||
38 | __cpuidle_driver_init(drv); | 59 | __cpuidle_driver_init(drv, cpu); |
39 | 60 | ||
40 | __cpuidle_set_cpu_driver(drv, cpu); | 61 | __cpuidle_set_cpu_driver(drv, cpu); |
41 | 62 | ||
@@ -49,6 +70,12 @@ static void __cpuidle_unregister_driver(struct cpuidle_driver *drv, int cpu) | |||
49 | 70 | ||
50 | if (!WARN_ON(drv->refcnt > 0)) | 71 | if (!WARN_ON(drv->refcnt > 0)) |
51 | __cpuidle_set_cpu_driver(NULL, cpu); | 72 | __cpuidle_set_cpu_driver(NULL, cpu); |
73 | |||
74 | if (drv->bctimer) { | ||
75 | drv->bctimer = 0; | ||
76 | on_each_cpu_mask(get_cpu_mask(cpu), cpuidle_setup_broadcast_timer, | ||
77 | (void *)CLOCK_EVT_NOTIFY_BROADCAST_OFF, 1); | ||
78 | } | ||
52 | } | 79 | } |
53 | 80 | ||
54 | #ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS | 81 | #ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS |
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index 66346521cb65..f9fd93758333 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h | |||
@@ -8,6 +8,20 @@ | |||
8 | #ifndef _LINUX_CLOCKCHIPS_H | 8 | #ifndef _LINUX_CLOCKCHIPS_H |
9 | #define _LINUX_CLOCKCHIPS_H | 9 | #define _LINUX_CLOCKCHIPS_H |
10 | 10 | ||
11 | /* Clock event notification values */ | ||
12 | enum clock_event_nofitiers { | ||
13 | CLOCK_EVT_NOTIFY_ADD, | ||
14 | CLOCK_EVT_NOTIFY_BROADCAST_ON, | ||
15 | CLOCK_EVT_NOTIFY_BROADCAST_OFF, | ||
16 | CLOCK_EVT_NOTIFY_BROADCAST_FORCE, | ||
17 | CLOCK_EVT_NOTIFY_BROADCAST_ENTER, | ||
18 | CLOCK_EVT_NOTIFY_BROADCAST_EXIT, | ||
19 | CLOCK_EVT_NOTIFY_SUSPEND, | ||
20 | CLOCK_EVT_NOTIFY_RESUME, | ||
21 | CLOCK_EVT_NOTIFY_CPU_DYING, | ||
22 | CLOCK_EVT_NOTIFY_CPU_DEAD, | ||
23 | }; | ||
24 | |||
11 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BUILD | 25 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BUILD |
12 | 26 | ||
13 | #include <linux/clocksource.h> | 27 | #include <linux/clocksource.h> |
@@ -26,20 +40,6 @@ enum clock_event_mode { | |||
26 | CLOCK_EVT_MODE_RESUME, | 40 | CLOCK_EVT_MODE_RESUME, |
27 | }; | 41 | }; |
28 | 42 | ||
29 | /* Clock event notification values */ | ||
30 | enum clock_event_nofitiers { | ||
31 | CLOCK_EVT_NOTIFY_ADD, | ||
32 | CLOCK_EVT_NOTIFY_BROADCAST_ON, | ||
33 | CLOCK_EVT_NOTIFY_BROADCAST_OFF, | ||
34 | CLOCK_EVT_NOTIFY_BROADCAST_FORCE, | ||
35 | CLOCK_EVT_NOTIFY_BROADCAST_ENTER, | ||
36 | CLOCK_EVT_NOTIFY_BROADCAST_EXIT, | ||
37 | CLOCK_EVT_NOTIFY_SUSPEND, | ||
38 | CLOCK_EVT_NOTIFY_RESUME, | ||
39 | CLOCK_EVT_NOTIFY_CPU_DYING, | ||
40 | CLOCK_EVT_NOTIFY_CPU_DEAD, | ||
41 | }; | ||
42 | |||
43 | /* | 43 | /* |
44 | * Clock event features | 44 | * Clock event features |
45 | */ | 45 | */ |
@@ -173,7 +173,7 @@ extern int tick_receive_broadcast(void); | |||
173 | #ifdef CONFIG_GENERIC_CLOCKEVENTS | 173 | #ifdef CONFIG_GENERIC_CLOCKEVENTS |
174 | extern void clockevents_notify(unsigned long reason, void *arg); | 174 | extern void clockevents_notify(unsigned long reason, void *arg); |
175 | #else | 175 | #else |
176 | # define clockevents_notify(reason, arg) do { } while (0) | 176 | static inline void clockevents_notify(unsigned long reason, void *arg) {} |
177 | #endif | 177 | #endif |
178 | 178 | ||
179 | #else /* CONFIG_GENERIC_CLOCKEVENTS_BUILD */ | 179 | #else /* CONFIG_GENERIC_CLOCKEVENTS_BUILD */ |
@@ -181,7 +181,7 @@ extern void clockevents_notify(unsigned long reason, void *arg); | |||
181 | static inline void clockevents_suspend(void) {} | 181 | static inline void clockevents_suspend(void) {} |
182 | static inline void clockevents_resume(void) {} | 182 | static inline void clockevents_resume(void) {} |
183 | 183 | ||
184 | #define clockevents_notify(reason, arg) do { } while (0) | 184 | static inline void clockevents_notify(unsigned long reason, void *arg) {} |
185 | 185 | ||
186 | #endif | 186 | #endif |
187 | 187 | ||
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 480c14dc1ddd..fc3e5808b7ff 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h | |||
@@ -57,6 +57,7 @@ struct cpuidle_state { | |||
57 | /* Idle State Flags */ | 57 | /* Idle State Flags */ |
58 | #define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */ | 58 | #define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */ |
59 | #define CPUIDLE_FLAG_COUPLED (0x02) /* state applies to multiple cpus */ | 59 | #define CPUIDLE_FLAG_COUPLED (0x02) /* state applies to multiple cpus */ |
60 | #define CPUIDLE_FLAG_TIMER_STOP (0x04) /* timer is stopped on this state */ | ||
60 | 61 | ||
61 | #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000) | 62 | #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000) |
62 | 63 | ||
@@ -106,6 +107,8 @@ struct cpuidle_driver { | |||
106 | 107 | ||
107 | /* set to 1 to use the core cpuidle time keeping (for all states). */ | 108 | /* set to 1 to use the core cpuidle time keeping (for all states). */ |
108 | unsigned int en_core_tk_irqen:1; | 109 | unsigned int en_core_tk_irqen:1; |
110 | /* used by the cpuidle framework to setup the broadcast timer */ | ||
111 | unsigned int bctimer:1; | ||
109 | /* states array must be ordered in decreasing power consumption */ | 112 | /* states array must be ordered in decreasing power consumption */ |
110 | struct cpuidle_state states[CPUIDLE_STATE_MAX]; | 113 | struct cpuidle_state states[CPUIDLE_STATE_MAX]; |
111 | int state_count; | 114 | int state_count; |