diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/processor_idle.c | 1 | ||||
-rw-r--r-- | drivers/cpuidle/Kconfig | 6 | ||||
-rw-r--r-- | drivers/cpuidle/Makefile | 2 | ||||
-rw-r--r-- | drivers/cpuidle/cpuidle-calxeda.c | 57 | ||||
-rw-r--r-- | drivers/cpuidle/cpuidle-kirkwood.c | 29 | ||||
-rw-r--r-- | drivers/cpuidle/cpuidle.c | 153 | ||||
-rw-r--r-- | drivers/cpuidle/driver.c | 31 | ||||
-rw-r--r-- | drivers/idle/intel_idle.c | 4 |
8 files changed, 141 insertions, 142 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index ee255c60bdac..f0df2c9434d2 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, | |||
918 | struct cpuidle_driver acpi_idle_driver = { | 918 | struct cpuidle_driver acpi_idle_driver = { |
919 | .name = "acpi_idle", | 919 | .name = "acpi_idle", |
920 | .owner = THIS_MODULE, | 920 | .owner = THIS_MODULE, |
921 | .en_core_tk_irqen = 1, | ||
922 | }; | 921 | }; |
923 | 922 | ||
924 | /** | 923 | /** |
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-calxeda.c b/drivers/cpuidle/cpuidle-calxeda.c index e1aab38c5a8d..223379169cb0 100644 --- a/drivers/cpuidle/cpuidle-calxeda.c +++ b/drivers/cpuidle/cpuidle-calxeda.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2012 Calxeda, Inc. | 2 | * Copyright 2012 Calxeda, Inc. |
3 | * | 3 | * |
4 | * Based on arch/arm/plat-mxc/cpuidle.c: | 4 | * Based on arch/arm/plat-mxc/cpuidle.c: #v3.7 |
5 | * Copyright 2012 Freescale Semiconductor, Inc. | 5 | * Copyright 2012 Freescale Semiconductor, Inc. |
6 | * Copyright 2012 Linaro Ltd. | 6 | * Copyright 2012 Linaro Ltd. |
7 | * | 7 | * |
@@ -16,6 +16,8 @@ | |||
16 | * | 16 | * |
17 | * You should have received a copy of the GNU General Public License along with | 17 | * You should have received a copy of the GNU General Public License along with |
18 | * this program. If not, see <http://www.gnu.org/licenses/>. | 18 | * this program. If not, see <http://www.gnu.org/licenses/>. |
19 | * | ||
20 | * Maintainer: Rob Herring <rob.herring@calxeda.com> | ||
19 | */ | 21 | */ |
20 | 22 | ||
21 | #include <linux/cpuidle.h> | 23 | #include <linux/cpuidle.h> |
@@ -35,8 +37,6 @@ | |||
35 | extern void highbank_set_cpu_jump(int cpu, void *jump_addr); | 37 | extern void highbank_set_cpu_jump(int cpu, void *jump_addr); |
36 | extern void *scu_base_addr; | 38 | extern void *scu_base_addr; |
37 | 39 | ||
38 | static struct cpuidle_device __percpu *calxeda_idle_cpuidle_devices; | ||
39 | |||
40 | static inline unsigned int get_auxcr(void) | 40 | static inline unsigned int get_auxcr(void) |
41 | { | 41 | { |
42 | unsigned int val; | 42 | unsigned int val; |
@@ -85,22 +85,8 @@ static int calxeda_pwrdown_idle(struct cpuidle_device *dev, | |||
85 | return index; | 85 | return index; |
86 | } | 86 | } |
87 | 87 | ||
88 | static void calxeda_idle_cpuidle_devices_uninit(void) | ||
89 | { | ||
90 | int i; | ||
91 | struct cpuidle_device *dev; | ||
92 | |||
93 | for_each_possible_cpu(i) { | ||
94 | dev = per_cpu_ptr(calxeda_idle_cpuidle_devices, i); | ||
95 | cpuidle_unregister_device(dev); | ||
96 | } | ||
97 | |||
98 | free_percpu(calxeda_idle_cpuidle_devices); | ||
99 | } | ||
100 | |||
101 | static struct cpuidle_driver calxeda_idle_driver = { | 88 | static struct cpuidle_driver calxeda_idle_driver = { |
102 | .name = "calxeda_idle", | 89 | .name = "calxeda_idle", |
103 | .en_core_tk_irqen = 1, | ||
104 | .states = { | 90 | .states = { |
105 | ARM_CPUIDLE_WFI_STATE, | 91 | ARM_CPUIDLE_WFI_STATE, |
106 | { | 92 | { |
@@ -118,44 +104,9 @@ static struct cpuidle_driver calxeda_idle_driver = { | |||
118 | 104 | ||
119 | static int __init calxeda_cpuidle_init(void) | 105 | static int __init calxeda_cpuidle_init(void) |
120 | { | 106 | { |
121 | int cpu_id; | ||
122 | int ret; | ||
123 | struct cpuidle_device *dev; | ||
124 | struct cpuidle_driver *drv = &calxeda_idle_driver; | ||
125 | |||
126 | if (!of_machine_is_compatible("calxeda,highbank")) | 107 | if (!of_machine_is_compatible("calxeda,highbank")) |
127 | return -ENODEV; | 108 | return -ENODEV; |
128 | 109 | ||
129 | ret = cpuidle_register_driver(drv); | 110 | return cpuidle_register(&calxeda_idle_driver, NULL); |
130 | if (ret) | ||
131 | return ret; | ||
132 | |||
133 | calxeda_idle_cpuidle_devices = alloc_percpu(struct cpuidle_device); | ||
134 | if (calxeda_idle_cpuidle_devices == NULL) { | ||
135 | ret = -ENOMEM; | ||
136 | goto unregister_drv; | ||
137 | } | ||
138 | |||
139 | /* initialize state data for each cpuidle_device */ | ||
140 | for_each_possible_cpu(cpu_id) { | ||
141 | dev = per_cpu_ptr(calxeda_idle_cpuidle_devices, cpu_id); | ||
142 | dev->cpu = cpu_id; | ||
143 | dev->state_count = drv->state_count; | ||
144 | |||
145 | ret = cpuidle_register_device(dev); | ||
146 | if (ret) { | ||
147 | pr_err("Failed to register cpu %u, error: %d\n", | ||
148 | cpu_id, ret); | ||
149 | goto uninit; | ||
150 | } | ||
151 | } | ||
152 | |||
153 | return 0; | ||
154 | |||
155 | uninit: | ||
156 | calxeda_idle_cpuidle_devices_uninit(); | ||
157 | unregister_drv: | ||
158 | cpuidle_unregister_driver(drv); | ||
159 | return ret; | ||
160 | } | 111 | } |
161 | module_init(calxeda_cpuidle_init); | 112 | module_init(calxeda_cpuidle_init); |
diff --git a/drivers/cpuidle/cpuidle-kirkwood.c b/drivers/cpuidle/cpuidle-kirkwood.c index 670aa1e55cd6..521b0a7fdd89 100644 --- a/drivers/cpuidle/cpuidle-kirkwood.c +++ b/drivers/cpuidle/cpuidle-kirkwood.c | |||
@@ -1,6 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * arch/arm/mach-kirkwood/cpuidle.c | ||
3 | * | ||
4 | * CPU idle Marvell Kirkwood SoCs | 2 | * CPU idle Marvell Kirkwood SoCs |
5 | * | 3 | * |
6 | * This file is licensed under the terms of the GNU General Public | 4 | * This file is licensed under the terms of the GNU General Public |
@@ -11,6 +9,9 @@ | |||
11 | * to implement two idle states - | 9 | * to implement two idle states - |
12 | * #1 wait-for-interrupt | 10 | * #1 wait-for-interrupt |
13 | * #2 wait-for-interrupt and DDR self refresh | 11 | * #2 wait-for-interrupt and DDR self refresh |
12 | * | ||
13 | * Maintainer: Jason Cooper <jason@lakedaemon.net> | ||
14 | * Maintainer: Andrew Lunn <andrew@lunn.ch> | ||
14 | */ | 15 | */ |
15 | 16 | ||
16 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
@@ -41,7 +42,6 @@ static int kirkwood_enter_idle(struct cpuidle_device *dev, | |||
41 | static struct cpuidle_driver kirkwood_idle_driver = { | 42 | static struct cpuidle_driver kirkwood_idle_driver = { |
42 | .name = "kirkwood_idle", | 43 | .name = "kirkwood_idle", |
43 | .owner = THIS_MODULE, | 44 | .owner = THIS_MODULE, |
44 | .en_core_tk_irqen = 1, | ||
45 | .states[0] = ARM_CPUIDLE_WFI_STATE, | 45 | .states[0] = ARM_CPUIDLE_WFI_STATE, |
46 | .states[1] = { | 46 | .states[1] = { |
47 | .enter = kirkwood_enter_idle, | 47 | .enter = kirkwood_enter_idle, |
@@ -53,9 +53,6 @@ static struct cpuidle_driver kirkwood_idle_driver = { | |||
53 | }, | 53 | }, |
54 | .state_count = KIRKWOOD_MAX_STATES, | 54 | .state_count = KIRKWOOD_MAX_STATES, |
55 | }; | 55 | }; |
56 | static struct cpuidle_device *device; | ||
57 | |||
58 | static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device); | ||
59 | 56 | ||
60 | /* Initialize CPU idle by registering the idle states */ | 57 | /* Initialize CPU idle by registering the idle states */ |
61 | static int kirkwood_cpuidle_probe(struct platform_device *pdev) | 58 | static int kirkwood_cpuidle_probe(struct platform_device *pdev) |
@@ -66,26 +63,16 @@ static int kirkwood_cpuidle_probe(struct platform_device *pdev) | |||
66 | if (res == NULL) | 63 | if (res == NULL) |
67 | return -EINVAL; | 64 | return -EINVAL; |
68 | 65 | ||
69 | ddr_operation_base = devm_request_and_ioremap(&pdev->dev, res); | 66 | ddr_operation_base = devm_ioremap_resource(&pdev->dev, res); |
70 | if (!ddr_operation_base) | 67 | if (IS_ERR(ddr_operation_base)) |
71 | return -EADDRNOTAVAIL; | 68 | return PTR_ERR(ddr_operation_base); |
72 | 69 | ||
73 | device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id()); | 70 | return cpuidle_register(&kirkwood_idle_driver, NULL); |
74 | device->state_count = KIRKWOOD_MAX_STATES; | ||
75 | |||
76 | cpuidle_register_driver(&kirkwood_idle_driver); | ||
77 | if (cpuidle_register_device(device)) { | ||
78 | pr_err("kirkwood_init_cpuidle: Failed registering\n"); | ||
79 | return -EIO; | ||
80 | } | ||
81 | return 0; | ||
82 | } | 71 | } |
83 | 72 | ||
84 | int kirkwood_cpuidle_remove(struct platform_device *pdev) | 73 | int kirkwood_cpuidle_remove(struct platform_device *pdev) |
85 | { | 74 | { |
86 | cpuidle_unregister_device(device); | 75 | cpuidle_unregister(&kirkwood_idle_driver); |
87 | cpuidle_unregister_driver(&kirkwood_idle_driver); | ||
88 | |||
89 | return 0; | 76 | return 0; |
90 | } | 77 | } |
91 | 78 | ||
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index eba69290e074..c3a93fece819 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> |
@@ -23,6 +24,7 @@ | |||
23 | #include "cpuidle.h" | 24 | #include "cpuidle.h" |
24 | 25 | ||
25 | DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices); | 26 | DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices); |
27 | DEFINE_PER_CPU(struct cpuidle_device, cpuidle_dev); | ||
26 | 28 | ||
27 | DEFINE_MUTEX(cpuidle_lock); | 29 | DEFINE_MUTEX(cpuidle_lock); |
28 | LIST_HEAD(cpuidle_detected_devices); | 30 | LIST_HEAD(cpuidle_detected_devices); |
@@ -42,24 +44,6 @@ void disable_cpuidle(void) | |||
42 | 44 | ||
43 | static int __cpuidle_register_device(struct cpuidle_device *dev); | 45 | static int __cpuidle_register_device(struct cpuidle_device *dev); |
44 | 46 | ||
45 | static inline int cpuidle_enter(struct cpuidle_device *dev, | ||
46 | struct cpuidle_driver *drv, int index) | ||
47 | { | ||
48 | struct cpuidle_state *target_state = &drv->states[index]; | ||
49 | return target_state->enter(dev, drv, index); | ||
50 | } | ||
51 | |||
52 | static inline int cpuidle_enter_tk(struct cpuidle_device *dev, | ||
53 | struct cpuidle_driver *drv, int index) | ||
54 | { | ||
55 | return cpuidle_wrap_enter(dev, drv, index, cpuidle_enter); | ||
56 | } | ||
57 | |||
58 | typedef int (*cpuidle_enter_t)(struct cpuidle_device *dev, | ||
59 | struct cpuidle_driver *drv, int index); | ||
60 | |||
61 | static cpuidle_enter_t cpuidle_enter_ops; | ||
62 | |||
63 | /** | 47 | /** |
64 | * cpuidle_play_dead - cpu off-lining | 48 | * cpuidle_play_dead - cpu off-lining |
65 | * | 49 | * |
@@ -89,11 +73,27 @@ int cpuidle_play_dead(void) | |||
89 | * @next_state: index into drv->states of the state to enter | 73 | * @next_state: index into drv->states of the state to enter |
90 | */ | 74 | */ |
91 | int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, | 75 | int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, |
92 | int next_state) | 76 | int index) |
93 | { | 77 | { |
94 | int entered_state; | 78 | int entered_state; |
95 | 79 | ||
96 | entered_state = cpuidle_enter_ops(dev, drv, next_state); | 80 | struct cpuidle_state *target_state = &drv->states[index]; |
81 | ktime_t time_start, time_end; | ||
82 | s64 diff; | ||
83 | |||
84 | time_start = ktime_get(); | ||
85 | |||
86 | entered_state = target_state->enter(dev, drv, index); | ||
87 | |||
88 | time_end = ktime_get(); | ||
89 | |||
90 | local_irq_enable(); | ||
91 | |||
92 | diff = ktime_to_us(ktime_sub(time_end, time_start)); | ||
93 | if (diff > INT_MAX) | ||
94 | diff = INT_MAX; | ||
95 | |||
96 | dev->last_residency = (int) diff; | ||
97 | 97 | ||
98 | if (entered_state >= 0) { | 98 | if (entered_state >= 0) { |
99 | /* Update cpuidle counters */ | 99 | /* Update cpuidle counters */ |
@@ -146,12 +146,20 @@ int cpuidle_idle_call(void) | |||
146 | 146 | ||
147 | trace_cpu_idle_rcuidle(next_state, dev->cpu); | 147 | trace_cpu_idle_rcuidle(next_state, dev->cpu); |
148 | 148 | ||
149 | if (drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP) | ||
150 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, | ||
151 | &dev->cpu); | ||
152 | |||
149 | if (cpuidle_state_is_coupled(dev, drv, next_state)) | 153 | if (cpuidle_state_is_coupled(dev, drv, next_state)) |
150 | entered_state = cpuidle_enter_state_coupled(dev, drv, | 154 | entered_state = cpuidle_enter_state_coupled(dev, drv, |
151 | next_state); | 155 | next_state); |
152 | else | 156 | else |
153 | entered_state = cpuidle_enter_state(dev, drv, next_state); | 157 | entered_state = cpuidle_enter_state(dev, drv, next_state); |
154 | 158 | ||
159 | if (drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP) | ||
160 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, | ||
161 | &dev->cpu); | ||
162 | |||
155 | trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); | 163 | trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); |
156 | 164 | ||
157 | /* give the governor an opportunity to reflect on the outcome */ | 165 | /* give the governor an opportunity to reflect on the outcome */ |
@@ -222,37 +230,6 @@ void cpuidle_resume(void) | |||
222 | mutex_unlock(&cpuidle_lock); | 230 | mutex_unlock(&cpuidle_lock); |
223 | } | 231 | } |
224 | 232 | ||
225 | /** | ||
226 | * cpuidle_wrap_enter - performs timekeeping and irqen around enter function | ||
227 | * @dev: pointer to a valid cpuidle_device object | ||
228 | * @drv: pointer to a valid cpuidle_driver object | ||
229 | * @index: index of the target cpuidle state. | ||
230 | */ | ||
231 | int cpuidle_wrap_enter(struct cpuidle_device *dev, | ||
232 | struct cpuidle_driver *drv, int index, | ||
233 | int (*enter)(struct cpuidle_device *dev, | ||
234 | struct cpuidle_driver *drv, int index)) | ||
235 | { | ||
236 | ktime_t time_start, time_end; | ||
237 | s64 diff; | ||
238 | |||
239 | time_start = ktime_get(); | ||
240 | |||
241 | index = enter(dev, drv, index); | ||
242 | |||
243 | time_end = ktime_get(); | ||
244 | |||
245 | local_irq_enable(); | ||
246 | |||
247 | diff = ktime_to_us(ktime_sub(time_end, time_start)); | ||
248 | if (diff > INT_MAX) | ||
249 | diff = INT_MAX; | ||
250 | |||
251 | dev->last_residency = (int) diff; | ||
252 | |||
253 | return index; | ||
254 | } | ||
255 | |||
256 | #ifdef CONFIG_ARCH_HAS_CPU_RELAX | 233 | #ifdef CONFIG_ARCH_HAS_CPU_RELAX |
257 | static int poll_idle(struct cpuidle_device *dev, | 234 | static int poll_idle(struct cpuidle_device *dev, |
258 | struct cpuidle_driver *drv, int index) | 235 | struct cpuidle_driver *drv, int index) |
@@ -324,9 +301,6 @@ int cpuidle_enable_device(struct cpuidle_device *dev) | |||
324 | return ret; | 301 | return ret; |
325 | } | 302 | } |
326 | 303 | ||
327 | cpuidle_enter_ops = drv->en_core_tk_irqen ? | ||
328 | cpuidle_enter_tk : cpuidle_enter; | ||
329 | |||
330 | poll_idle_init(drv); | 304 | poll_idle_init(drv); |
331 | 305 | ||
332 | ret = cpuidle_add_device_sysfs(dev); | 306 | ret = cpuidle_add_device_sysfs(dev); |
@@ -480,6 +454,77 @@ void cpuidle_unregister_device(struct cpuidle_device *dev) | |||
480 | 454 | ||
481 | EXPORT_SYMBOL_GPL(cpuidle_unregister_device); | 455 | EXPORT_SYMBOL_GPL(cpuidle_unregister_device); |
482 | 456 | ||
457 | /** | ||
458 | * cpuidle_unregister: unregister a driver and the devices. This function | ||
459 | * can be used only if the driver has been previously registered through | ||
460 | * the cpuidle_register function. | ||
461 | * | ||
462 | * @drv: a valid pointer to a struct cpuidle_driver | ||
463 | */ | ||
464 | void cpuidle_unregister(struct cpuidle_driver *drv) | ||
465 | { | ||
466 | int cpu; | ||
467 | struct cpuidle_device *device; | ||
468 | |||
469 | for_each_possible_cpu(cpu) { | ||
470 | device = &per_cpu(cpuidle_dev, cpu); | ||
471 | cpuidle_unregister_device(device); | ||
472 | } | ||
473 | |||
474 | cpuidle_unregister_driver(drv); | ||
475 | } | ||
476 | EXPORT_SYMBOL_GPL(cpuidle_unregister); | ||
477 | |||
478 | /** | ||
479 | * cpuidle_register: registers the driver and the cpu devices with the | ||
480 | * coupled_cpus passed as parameter. This function is used for all common | ||
481 | * initialization pattern there are in the arch specific drivers. The | ||
482 | * devices is globally defined in this file. | ||
483 | * | ||
484 | * @drv : a valid pointer to a struct cpuidle_driver | ||
485 | * @coupled_cpus: a cpumask for the coupled states | ||
486 | * | ||
487 | * Returns 0 on success, < 0 otherwise | ||
488 | */ | ||
489 | int cpuidle_register(struct cpuidle_driver *drv, | ||
490 | const struct cpumask *const coupled_cpus) | ||
491 | { | ||
492 | int ret, cpu; | ||
493 | struct cpuidle_device *device; | ||
494 | |||
495 | ret = cpuidle_register_driver(drv); | ||
496 | if (ret) { | ||
497 | pr_err("failed to register cpuidle driver\n"); | ||
498 | return ret; | ||
499 | } | ||
500 | |||
501 | for_each_possible_cpu(cpu) { | ||
502 | device = &per_cpu(cpuidle_dev, cpu); | ||
503 | device->cpu = cpu; | ||
504 | |||
505 | #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED | ||
506 | /* | ||
507 | * On multiplatform for ARM, the coupled idle states could | ||
508 | * enabled in the kernel even if the cpuidle driver does not | ||
509 | * use it. Note, coupled_cpus is a struct copy. | ||
510 | */ | ||
511 | if (coupled_cpus) | ||
512 | device->coupled_cpus = *coupled_cpus; | ||
513 | #endif | ||
514 | ret = cpuidle_register_device(device); | ||
515 | if (!ret) | ||
516 | continue; | ||
517 | |||
518 | pr_err("Failed to register cpuidle device for cpu%d\n", cpu); | ||
519 | |||
520 | cpuidle_unregister(drv); | ||
521 | break; | ||
522 | } | ||
523 | |||
524 | return ret; | ||
525 | } | ||
526 | EXPORT_SYMBOL_GPL(cpuidle_register); | ||
527 | |||
483 | #ifdef CONFIG_SMP | 528 | #ifdef CONFIG_SMP |
484 | 529 | ||
485 | static void smp_callback(void *v) | 530 | static void smp_callback(void *v) |
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/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 1a38dd7dfe4e..0e8fab1913df 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c | |||
@@ -71,7 +71,6 @@ | |||
71 | static struct cpuidle_driver intel_idle_driver = { | 71 | static struct cpuidle_driver intel_idle_driver = { |
72 | .name = "intel_idle", | 72 | .name = "intel_idle", |
73 | .owner = THIS_MODULE, | 73 | .owner = THIS_MODULE, |
74 | .en_core_tk_irqen = 1, | ||
75 | }; | 74 | }; |
76 | /* intel_idle.max_cstate=0 disables driver */ | 75 | /* intel_idle.max_cstate=0 disables driver */ |
77 | static int max_cstate = CPUIDLE_STATE_MAX - 1; | 76 | static int max_cstate = CPUIDLE_STATE_MAX - 1; |
@@ -339,7 +338,6 @@ static int intel_idle(struct cpuidle_device *dev, | |||
339 | if (!(lapic_timer_reliable_states & (1 << (cstate)))) | 338 | if (!(lapic_timer_reliable_states & (1 << (cstate)))) |
340 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); | 339 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); |
341 | 340 | ||
342 | stop_critical_timings(); | ||
343 | if (!need_resched()) { | 341 | if (!need_resched()) { |
344 | 342 | ||
345 | __monitor((void *)¤t_thread_info()->flags, 0, 0); | 343 | __monitor((void *)¤t_thread_info()->flags, 0, 0); |
@@ -348,8 +346,6 @@ static int intel_idle(struct cpuidle_device *dev, | |||
348 | __mwait(eax, ecx); | 346 | __mwait(eax, ecx); |
349 | } | 347 | } |
350 | 348 | ||
351 | start_critical_timings(); | ||
352 | |||
353 | if (!(lapic_timer_reliable_states & (1 << (cstate)))) | 349 | if (!(lapic_timer_reliable_states & (1 << (cstate)))) |
354 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); | 350 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); |
355 | 351 | ||