diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/Kconfig | 12 | ||||
-rw-r--r-- | arch/arm/include/asm/localtimer.h | 34 | ||||
-rw-r--r-- | arch/arm/kernel/smp.c | 87 | ||||
-rw-r--r-- | arch/arm/kernel/smp_twd.c | 64 | ||||
-rw-r--r-- | arch/arm/mach-highbank/Kconfig | 2 | ||||
-rw-r--r-- | arch/arm/mach-imx/Kconfig | 3 | ||||
-rw-r--r-- | arch/arm/mach-msm/timer.c | 124 | ||||
-rw-r--r-- | arch/arm/mach-omap2/Kconfig | 3 | ||||
-rw-r--r-- | arch/arm/mach-omap2/timer.c | 7 | ||||
-rw-r--r-- | arch/arm/mach-realview/Kconfig | 8 | ||||
-rw-r--r-- | arch/arm/mach-spear/Kconfig | 2 | ||||
-rw-r--r-- | arch/arm/mach-tegra/Kconfig | 2 | ||||
-rw-r--r-- | arch/arm/mach-ux500/Kconfig | 2 | ||||
-rw-r--r-- | arch/arm/mach-vexpress/Kconfig | 2 | ||||
-rw-r--r-- | arch/arm/mach-zynq/Kconfig | 2 |
15 files changed, 126 insertions, 228 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index ba412e02ec0c..baf43de26a54 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -645,7 +645,7 @@ config ARCH_SHMOBILE | |||
645 | select CLKDEV_LOOKUP | 645 | select CLKDEV_LOOKUP |
646 | select GENERIC_CLOCKEVENTS | 646 | select GENERIC_CLOCKEVENTS |
647 | select HAVE_ARM_SCU if SMP | 647 | select HAVE_ARM_SCU if SMP |
648 | select HAVE_ARM_TWD if LOCAL_TIMERS | 648 | select HAVE_ARM_TWD if SMP |
649 | select HAVE_CLK | 649 | select HAVE_CLK |
650 | select HAVE_MACH_CLKDEV | 650 | select HAVE_MACH_CLKDEV |
651 | select HAVE_SMP | 651 | select HAVE_SMP |
@@ -1584,16 +1584,6 @@ config ARM_PSCI | |||
1584 | 0022A ("Power State Coordination Interface System Software on | 1584 | 0022A ("Power State Coordination Interface System Software on |
1585 | ARM processors"). | 1585 | ARM processors"). |
1586 | 1586 | ||
1587 | config LOCAL_TIMERS | ||
1588 | bool "Use local timer interrupts" | ||
1589 | depends on SMP | ||
1590 | default y | ||
1591 | help | ||
1592 | Enable support for local timers on SMP platforms, rather then the | ||
1593 | legacy IPI broadcast method. Local timers allows the system | ||
1594 | accounting to be spread across the timer interval, preventing a | ||
1595 | "thundering herd" at every timer tick. | ||
1596 | |||
1597 | # The GPIO number here must be sorted by descending number. In case of | 1587 | # The GPIO number here must be sorted by descending number. In case of |
1598 | # a multiplatform kernel, we just want the highest value required by the | 1588 | # a multiplatform kernel, we just want the highest value required by the |
1599 | # selected platforms. | 1589 | # selected platforms. |
diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h deleted file mode 100644 index f77ffc1eb0c2..000000000000 --- a/arch/arm/include/asm/localtimer.h +++ /dev/null | |||
@@ -1,34 +0,0 @@ | |||
1 | /* | ||
2 | * arch/arm/include/asm/localtimer.h | ||
3 | * | ||
4 | * Copyright (C) 2004-2005 ARM Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | #ifndef __ASM_ARM_LOCALTIMER_H | ||
11 | #define __ASM_ARM_LOCALTIMER_H | ||
12 | |||
13 | #include <linux/errno.h> | ||
14 | |||
15 | struct clock_event_device; | ||
16 | |||
17 | struct local_timer_ops { | ||
18 | int (*setup)(struct clock_event_device *); | ||
19 | void (*stop)(struct clock_event_device *); | ||
20 | }; | ||
21 | |||
22 | #ifdef CONFIG_LOCAL_TIMERS | ||
23 | /* | ||
24 | * Register a local timer driver | ||
25 | */ | ||
26 | int local_timer_register(struct local_timer_ops *); | ||
27 | #else | ||
28 | static inline int local_timer_register(struct local_timer_ops *ops) | ||
29 | { | ||
30 | return -ENXIO; | ||
31 | } | ||
32 | #endif | ||
33 | |||
34 | #endif | ||
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index c2b4f8f0be9a..3a98192a3118 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c | |||
@@ -41,7 +41,6 @@ | |||
41 | #include <asm/sections.h> | 41 | #include <asm/sections.h> |
42 | #include <asm/tlbflush.h> | 42 | #include <asm/tlbflush.h> |
43 | #include <asm/ptrace.h> | 43 | #include <asm/ptrace.h> |
44 | #include <asm/localtimer.h> | ||
45 | #include <asm/smp_plat.h> | 44 | #include <asm/smp_plat.h> |
46 | #include <asm/virt.h> | 45 | #include <asm/virt.h> |
47 | #include <asm/mach/arch.h> | 46 | #include <asm/mach/arch.h> |
@@ -146,8 +145,6 @@ int boot_secondary(unsigned int cpu, struct task_struct *idle) | |||
146 | } | 145 | } |
147 | 146 | ||
148 | #ifdef CONFIG_HOTPLUG_CPU | 147 | #ifdef CONFIG_HOTPLUG_CPU |
149 | static void percpu_timer_stop(void); | ||
150 | |||
151 | static int platform_cpu_kill(unsigned int cpu) | 148 | static int platform_cpu_kill(unsigned int cpu) |
152 | { | 149 | { |
153 | if (smp_ops.cpu_kill) | 150 | if (smp_ops.cpu_kill) |
@@ -191,11 +188,6 @@ int __cpu_disable(void) | |||
191 | migrate_irqs(); | 188 | migrate_irqs(); |
192 | 189 | ||
193 | /* | 190 | /* |
194 | * Stop the local timer for this CPU. | ||
195 | */ | ||
196 | percpu_timer_stop(); | ||
197 | |||
198 | /* | ||
199 | * Flush user cache and TLB mappings, and then remove this CPU | 191 | * Flush user cache and TLB mappings, and then remove this CPU |
200 | * from the vm mask set of all processes. | 192 | * from the vm mask set of all processes. |
201 | * | 193 | * |
@@ -316,8 +308,6 @@ static void smp_store_cpu_info(unsigned int cpuid) | |||
316 | store_cpu_topology(cpuid); | 308 | store_cpu_topology(cpuid); |
317 | } | 309 | } |
318 | 310 | ||
319 | static void percpu_timer_setup(void); | ||
320 | |||
321 | /* | 311 | /* |
322 | * This is the secondary CPU boot entry. We're using this CPUs | 312 | * This is the secondary CPU boot entry. We're using this CPUs |
323 | * idle thread stack, but a set of temporary page tables. | 313 | * idle thread stack, but a set of temporary page tables. |
@@ -372,11 +362,6 @@ asmlinkage void secondary_start_kernel(void) | |||
372 | set_cpu_online(cpu, true); | 362 | set_cpu_online(cpu, true); |
373 | complete(&cpu_running); | 363 | complete(&cpu_running); |
374 | 364 | ||
375 | /* | ||
376 | * Setup the percpu timer for this CPU. | ||
377 | */ | ||
378 | percpu_timer_setup(); | ||
379 | |||
380 | local_irq_enable(); | 365 | local_irq_enable(); |
381 | local_fiq_enable(); | 366 | local_fiq_enable(); |
382 | 367 | ||
@@ -423,12 +408,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
423 | max_cpus = ncores; | 408 | max_cpus = ncores; |
424 | if (ncores > 1 && max_cpus) { | 409 | if (ncores > 1 && max_cpus) { |
425 | /* | 410 | /* |
426 | * Enable the local timer or broadcast device for the | ||
427 | * boot CPU, but only if we have more than one CPU. | ||
428 | */ | ||
429 | percpu_timer_setup(); | ||
430 | |||
431 | /* | ||
432 | * Initialise the present map, which describes the set of CPUs | 411 | * Initialise the present map, which describes the set of CPUs |
433 | * actually populated at the present time. A platform should | 412 | * actually populated at the present time. A platform should |
434 | * re-initialize the map in the platforms smp_prepare_cpus() | 413 | * re-initialize the map in the platforms smp_prepare_cpus() |
@@ -504,11 +483,6 @@ u64 smp_irq_stat_cpu(unsigned int cpu) | |||
504 | return sum; | 483 | return sum; |
505 | } | 484 | } |
506 | 485 | ||
507 | /* | ||
508 | * Timer (local or broadcast) support | ||
509 | */ | ||
510 | static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent); | ||
511 | |||
512 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST | 486 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST |
513 | void tick_broadcast(const struct cpumask *mask) | 487 | void tick_broadcast(const struct cpumask *mask) |
514 | { | 488 | { |
@@ -516,67 +490,6 @@ void tick_broadcast(const struct cpumask *mask) | |||
516 | } | 490 | } |
517 | #endif | 491 | #endif |
518 | 492 | ||
519 | static void broadcast_timer_set_mode(enum clock_event_mode mode, | ||
520 | struct clock_event_device *evt) | ||
521 | { | ||
522 | } | ||
523 | |||
524 | static void broadcast_timer_setup(struct clock_event_device *evt) | ||
525 | { | ||
526 | evt->name = "dummy_timer"; | ||
527 | evt->features = CLOCK_EVT_FEAT_ONESHOT | | ||
528 | CLOCK_EVT_FEAT_PERIODIC | | ||
529 | CLOCK_EVT_FEAT_DUMMY; | ||
530 | evt->rating = 100; | ||
531 | evt->mult = 1; | ||
532 | evt->set_mode = broadcast_timer_set_mode; | ||
533 | |||
534 | clockevents_register_device(evt); | ||
535 | } | ||
536 | |||
537 | static struct local_timer_ops *lt_ops; | ||
538 | |||
539 | #ifdef CONFIG_LOCAL_TIMERS | ||
540 | int local_timer_register(struct local_timer_ops *ops) | ||
541 | { | ||
542 | if (!is_smp() || !setup_max_cpus) | ||
543 | return -ENXIO; | ||
544 | |||
545 | if (lt_ops) | ||
546 | return -EBUSY; | ||
547 | |||
548 | lt_ops = ops; | ||
549 | return 0; | ||
550 | } | ||
551 | #endif | ||
552 | |||
553 | static void percpu_timer_setup(void) | ||
554 | { | ||
555 | unsigned int cpu = smp_processor_id(); | ||
556 | struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); | ||
557 | |||
558 | evt->cpumask = cpumask_of(cpu); | ||
559 | |||
560 | if (!lt_ops || lt_ops->setup(evt)) | ||
561 | broadcast_timer_setup(evt); | ||
562 | } | ||
563 | |||
564 | #ifdef CONFIG_HOTPLUG_CPU | ||
565 | /* | ||
566 | * The generic clock events code purposely does not stop the local timer | ||
567 | * on CPU_DEAD/CPU_DEAD_FROZEN hotplug events, so we have to do it | ||
568 | * manually here. | ||
569 | */ | ||
570 | static void percpu_timer_stop(void) | ||
571 | { | ||
572 | unsigned int cpu = smp_processor_id(); | ||
573 | struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); | ||
574 | |||
575 | if (lt_ops) | ||
576 | lt_ops->stop(evt); | ||
577 | } | ||
578 | #endif | ||
579 | |||
580 | static DEFINE_RAW_SPINLOCK(stop_lock); | 493 | static DEFINE_RAW_SPINLOCK(stop_lock); |
581 | 494 | ||
582 | /* | 495 | /* |
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 25956204ef23..2985c9f0905d 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/clk.h> | 13 | #include <linux/clk.h> |
14 | #include <linux/cpu.h> | ||
14 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
15 | #include <linux/device.h> | 16 | #include <linux/device.h> |
16 | #include <linux/err.h> | 17 | #include <linux/err.h> |
@@ -24,7 +25,6 @@ | |||
24 | 25 | ||
25 | #include <asm/smp_plat.h> | 26 | #include <asm/smp_plat.h> |
26 | #include <asm/smp_twd.h> | 27 | #include <asm/smp_twd.h> |
27 | #include <asm/localtimer.h> | ||
28 | 28 | ||
29 | /* set up by the platform code */ | 29 | /* set up by the platform code */ |
30 | static void __iomem *twd_base; | 30 | static void __iomem *twd_base; |
@@ -33,7 +33,7 @@ static struct clk *twd_clk; | |||
33 | static unsigned long twd_timer_rate; | 33 | static unsigned long twd_timer_rate; |
34 | static DEFINE_PER_CPU(bool, percpu_setup_called); | 34 | static DEFINE_PER_CPU(bool, percpu_setup_called); |
35 | 35 | ||
36 | static struct clock_event_device __percpu **twd_evt; | 36 | static struct clock_event_device __percpu *twd_evt; |
37 | static int twd_ppi; | 37 | static int twd_ppi; |
38 | 38 | ||
39 | static void twd_set_mode(enum clock_event_mode mode, | 39 | static void twd_set_mode(enum clock_event_mode mode, |
@@ -90,8 +90,10 @@ static int twd_timer_ack(void) | |||
90 | return 0; | 90 | return 0; |
91 | } | 91 | } |
92 | 92 | ||
93 | static void twd_timer_stop(struct clock_event_device *clk) | 93 | static void twd_timer_stop(void) |
94 | { | 94 | { |
95 | struct clock_event_device *clk = __this_cpu_ptr(twd_evt); | ||
96 | |||
95 | twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk); | 97 | twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk); |
96 | disable_percpu_irq(clk->irq); | 98 | disable_percpu_irq(clk->irq); |
97 | } | 99 | } |
@@ -106,7 +108,7 @@ static void twd_update_frequency(void *new_rate) | |||
106 | { | 108 | { |
107 | twd_timer_rate = *((unsigned long *) new_rate); | 109 | twd_timer_rate = *((unsigned long *) new_rate); |
108 | 110 | ||
109 | clockevents_update_freq(*__this_cpu_ptr(twd_evt), twd_timer_rate); | 111 | clockevents_update_freq(__this_cpu_ptr(twd_evt), twd_timer_rate); |
110 | } | 112 | } |
111 | 113 | ||
112 | static int twd_rate_change(struct notifier_block *nb, | 114 | static int twd_rate_change(struct notifier_block *nb, |
@@ -132,7 +134,7 @@ static struct notifier_block twd_clk_nb = { | |||
132 | 134 | ||
133 | static int twd_clk_init(void) | 135 | static int twd_clk_init(void) |
134 | { | 136 | { |
135 | if (twd_evt && *__this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk)) | 137 | if (twd_evt && __this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk)) |
136 | return clk_notifier_register(twd_clk, &twd_clk_nb); | 138 | return clk_notifier_register(twd_clk, &twd_clk_nb); |
137 | 139 | ||
138 | return 0; | 140 | return 0; |
@@ -151,7 +153,7 @@ static void twd_update_frequency(void *data) | |||
151 | { | 153 | { |
152 | twd_timer_rate = clk_get_rate(twd_clk); | 154 | twd_timer_rate = clk_get_rate(twd_clk); |
153 | 155 | ||
154 | clockevents_update_freq(*__this_cpu_ptr(twd_evt), twd_timer_rate); | 156 | clockevents_update_freq(__this_cpu_ptr(twd_evt), twd_timer_rate); |
155 | } | 157 | } |
156 | 158 | ||
157 | static int twd_cpufreq_transition(struct notifier_block *nb, | 159 | static int twd_cpufreq_transition(struct notifier_block *nb, |
@@ -177,7 +179,7 @@ static struct notifier_block twd_cpufreq_nb = { | |||
177 | 179 | ||
178 | static int twd_cpufreq_init(void) | 180 | static int twd_cpufreq_init(void) |
179 | { | 181 | { |
180 | if (twd_evt && *__this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk)) | 182 | if (twd_evt && __this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk)) |
181 | return cpufreq_register_notifier(&twd_cpufreq_nb, | 183 | return cpufreq_register_notifier(&twd_cpufreq_nb, |
182 | CPUFREQ_TRANSITION_NOTIFIER); | 184 | CPUFREQ_TRANSITION_NOTIFIER); |
183 | 185 | ||
@@ -228,7 +230,7 @@ static void twd_calibrate_rate(void) | |||
228 | 230 | ||
229 | static irqreturn_t twd_handler(int irq, void *dev_id) | 231 | static irqreturn_t twd_handler(int irq, void *dev_id) |
230 | { | 232 | { |
231 | struct clock_event_device *evt = *(struct clock_event_device **)dev_id; | 233 | struct clock_event_device *evt = dev_id; |
232 | 234 | ||
233 | if (twd_timer_ack()) { | 235 | if (twd_timer_ack()) { |
234 | evt->event_handler(evt); | 236 | evt->event_handler(evt); |
@@ -265,9 +267,9 @@ static void twd_get_clock(struct device_node *np) | |||
265 | /* | 267 | /* |
266 | * Setup the local clock events for a CPU. | 268 | * Setup the local clock events for a CPU. |
267 | */ | 269 | */ |
268 | static int twd_timer_setup(struct clock_event_device *clk) | 270 | static void twd_timer_setup(void) |
269 | { | 271 | { |
270 | struct clock_event_device **this_cpu_clk; | 272 | struct clock_event_device *clk = __this_cpu_ptr(twd_evt); |
271 | int cpu = smp_processor_id(); | 273 | int cpu = smp_processor_id(); |
272 | 274 | ||
273 | /* | 275 | /* |
@@ -276,9 +278,9 @@ static int twd_timer_setup(struct clock_event_device *clk) | |||
276 | */ | 278 | */ |
277 | if (per_cpu(percpu_setup_called, cpu)) { | 279 | if (per_cpu(percpu_setup_called, cpu)) { |
278 | __raw_writel(0, twd_base + TWD_TIMER_CONTROL); | 280 | __raw_writel(0, twd_base + TWD_TIMER_CONTROL); |
279 | clockevents_register_device(*__this_cpu_ptr(twd_evt)); | 281 | clockevents_register_device(clk); |
280 | enable_percpu_irq(clk->irq, 0); | 282 | enable_percpu_irq(clk->irq, 0); |
281 | return 0; | 283 | return; |
282 | } | 284 | } |
283 | per_cpu(percpu_setup_called, cpu) = true; | 285 | per_cpu(percpu_setup_called, cpu) = true; |
284 | 286 | ||
@@ -297,27 +299,37 @@ static int twd_timer_setup(struct clock_event_device *clk) | |||
297 | clk->set_mode = twd_set_mode; | 299 | clk->set_mode = twd_set_mode; |
298 | clk->set_next_event = twd_set_next_event; | 300 | clk->set_next_event = twd_set_next_event; |
299 | clk->irq = twd_ppi; | 301 | clk->irq = twd_ppi; |
300 | 302 | clk->cpumask = cpumask_of(cpu); | |
301 | this_cpu_clk = __this_cpu_ptr(twd_evt); | ||
302 | *this_cpu_clk = clk; | ||
303 | 303 | ||
304 | clockevents_config_and_register(clk, twd_timer_rate, | 304 | clockevents_config_and_register(clk, twd_timer_rate, |
305 | 0xf, 0xffffffff); | 305 | 0xf, 0xffffffff); |
306 | enable_percpu_irq(clk->irq, 0); | 306 | enable_percpu_irq(clk->irq, 0); |
307 | } | ||
307 | 308 | ||
308 | return 0; | 309 | static int twd_timer_cpu_notify(struct notifier_block *self, |
310 | unsigned long action, void *hcpu) | ||
311 | { | ||
312 | switch (action & ~CPU_TASKS_FROZEN) { | ||
313 | case CPU_STARTING: | ||
314 | twd_timer_setup(); | ||
315 | break; | ||
316 | case CPU_DYING: | ||
317 | twd_timer_stop(); | ||
318 | break; | ||
319 | } | ||
320 | |||
321 | return NOTIFY_OK; | ||
309 | } | 322 | } |
310 | 323 | ||
311 | static struct local_timer_ops twd_lt_ops = { | 324 | static struct notifier_block twd_timer_cpu_nb = { |
312 | .setup = twd_timer_setup, | 325 | .notifier_call = twd_timer_cpu_notify, |
313 | .stop = twd_timer_stop, | ||
314 | }; | 326 | }; |
315 | 327 | ||
316 | static int __init twd_local_timer_common_register(struct device_node *np) | 328 | static int __init twd_local_timer_common_register(struct device_node *np) |
317 | { | 329 | { |
318 | int err; | 330 | int err; |
319 | 331 | ||
320 | twd_evt = alloc_percpu(struct clock_event_device *); | 332 | twd_evt = alloc_percpu(struct clock_event_device); |
321 | if (!twd_evt) { | 333 | if (!twd_evt) { |
322 | err = -ENOMEM; | 334 | err = -ENOMEM; |
323 | goto out_free; | 335 | goto out_free; |
@@ -329,12 +341,22 @@ static int __init twd_local_timer_common_register(struct device_node *np) | |||
329 | goto out_free; | 341 | goto out_free; |
330 | } | 342 | } |
331 | 343 | ||
332 | err = local_timer_register(&twd_lt_ops); | 344 | err = register_cpu_notifier(&twd_timer_cpu_nb); |
333 | if (err) | 345 | if (err) |
334 | goto out_irq; | 346 | goto out_irq; |
335 | 347 | ||
336 | twd_get_clock(np); | 348 | twd_get_clock(np); |
337 | 349 | ||
350 | /* | ||
351 | * Immediately configure the timer on the boot CPU, unless we need | ||
352 | * jiffies to be incrementing to calibrate the rate in which case | ||
353 | * setup the timer in late_time_init. | ||
354 | */ | ||
355 | if (twd_timer_rate) | ||
356 | twd_timer_setup(); | ||
357 | else | ||
358 | late_time_init = twd_timer_setup; | ||
359 | |||
338 | return 0; | 360 | return 0; |
339 | 361 | ||
340 | out_irq: | 362 | out_irq: |
diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig index cd9fcb1cd7ab..6acbdabf6222 100644 --- a/arch/arm/mach-highbank/Kconfig +++ b/arch/arm/mach-highbank/Kconfig | |||
@@ -12,7 +12,7 @@ config ARCH_HIGHBANK | |||
12 | select CPU_V7 | 12 | select CPU_V7 |
13 | select GENERIC_CLOCKEVENTS | 13 | select GENERIC_CLOCKEVENTS |
14 | select HAVE_ARM_SCU | 14 | select HAVE_ARM_SCU |
15 | select HAVE_ARM_TWD if LOCAL_TIMERS | 15 | select HAVE_ARM_TWD if SMP |
16 | select HAVE_SMP | 16 | select HAVE_SMP |
17 | select MAILBOX | 17 | select MAILBOX |
18 | select PL320_MBOX | 18 | select PL320_MBOX |
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index f54656091a9d..21fa9fa3d54e 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig | |||
@@ -793,7 +793,8 @@ config SOC_IMX6Q | |||
793 | select COMMON_CLK | 793 | select COMMON_CLK |
794 | select CPU_V7 | 794 | select CPU_V7 |
795 | select HAVE_ARM_SCU if SMP | 795 | select HAVE_ARM_SCU if SMP |
796 | select HAVE_ARM_TWD if LOCAL_TIMERS | 796 | select HAVE_ARM_TWD if SMP |
797 | select HAVE_CAN_FLEXCAN if CAN | ||
797 | select HAVE_IMX_ANATOP | 798 | select HAVE_IMX_ANATOP |
798 | select HAVE_IMX_GPC | 799 | select HAVE_IMX_GPC |
799 | select HAVE_IMX_MMDC | 800 | select HAVE_IMX_MMDC |
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 8697cfc0d0b6..a7afbacae61a 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #include <linux/clocksource.h> | 17 | #include <linux/clocksource.h> |
18 | #include <linux/clockchips.h> | 18 | #include <linux/clockchips.h> |
19 | #include <linux/cpu.h> | ||
19 | #include <linux/init.h> | 20 | #include <linux/init.h> |
20 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
21 | #include <linux/irq.h> | 22 | #include <linux/irq.h> |
@@ -26,7 +27,6 @@ | |||
26 | #include <linux/sched_clock.h> | 27 | #include <linux/sched_clock.h> |
27 | 28 | ||
28 | #include <asm/mach/time.h> | 29 | #include <asm/mach/time.h> |
29 | #include <asm/localtimer.h> | ||
30 | 30 | ||
31 | #include "common.h" | 31 | #include "common.h" |
32 | 32 | ||
@@ -49,7 +49,7 @@ static void __iomem *sts_base; | |||
49 | 49 | ||
50 | static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) | 50 | static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) |
51 | { | 51 | { |
52 | struct clock_event_device *evt = *(struct clock_event_device **)dev_id; | 52 | struct clock_event_device *evt = dev_id; |
53 | /* Stop the timer tick */ | 53 | /* Stop the timer tick */ |
54 | if (evt->mode == CLOCK_EVT_MODE_ONESHOT) { | 54 | if (evt->mode == CLOCK_EVT_MODE_ONESHOT) { |
55 | u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE); | 55 | u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE); |
@@ -101,18 +101,7 @@ static void msm_timer_set_mode(enum clock_event_mode mode, | |||
101 | writel_relaxed(ctrl, event_base + TIMER_ENABLE); | 101 | writel_relaxed(ctrl, event_base + TIMER_ENABLE); |
102 | } | 102 | } |
103 | 103 | ||
104 | static struct clock_event_device msm_clockevent = { | 104 | static struct clock_event_device __percpu *msm_evt; |
105 | .name = "gp_timer", | ||
106 | .features = CLOCK_EVT_FEAT_ONESHOT, | ||
107 | .rating = 200, | ||
108 | .set_next_event = msm_timer_set_next_event, | ||
109 | .set_mode = msm_timer_set_mode, | ||
110 | }; | ||
111 | |||
112 | static union { | ||
113 | struct clock_event_device *evt; | ||
114 | struct clock_event_device * __percpu *percpu_evt; | ||
115 | } msm_evt; | ||
116 | 105 | ||
117 | static void __iomem *source_base; | 106 | static void __iomem *source_base; |
118 | 107 | ||
@@ -138,23 +127,34 @@ static struct clocksource msm_clocksource = { | |||
138 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 127 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
139 | }; | 128 | }; |
140 | 129 | ||
141 | #ifdef CONFIG_LOCAL_TIMERS | 130 | static int msm_timer_irq; |
131 | static int msm_timer_has_ppi; | ||
132 | |||
142 | static int msm_local_timer_setup(struct clock_event_device *evt) | 133 | static int msm_local_timer_setup(struct clock_event_device *evt) |
143 | { | 134 | { |
144 | /* Use existing clock_event for cpu 0 */ | 135 | int cpu = smp_processor_id(); |
145 | if (!smp_processor_id()) | 136 | int err; |
146 | return 0; | 137 | |
147 | 138 | evt->irq = msm_timer_irq; | |
148 | evt->irq = msm_clockevent.irq; | 139 | evt->name = "msm_timer"; |
149 | evt->name = "local_timer"; | 140 | evt->features = CLOCK_EVT_FEAT_ONESHOT; |
150 | evt->features = msm_clockevent.features; | 141 | evt->rating = 200; |
151 | evt->rating = msm_clockevent.rating; | ||
152 | evt->set_mode = msm_timer_set_mode; | 142 | evt->set_mode = msm_timer_set_mode; |
153 | evt->set_next_event = msm_timer_set_next_event; | 143 | evt->set_next_event = msm_timer_set_next_event; |
144 | evt->cpumask = cpumask_of(cpu); | ||
145 | |||
146 | clockevents_config_and_register(evt, GPT_HZ, 4, 0xffffffff); | ||
147 | |||
148 | if (msm_timer_has_ppi) { | ||
149 | enable_percpu_irq(evt->irq, IRQ_TYPE_EDGE_RISING); | ||
150 | } else { | ||
151 | err = request_irq(evt->irq, msm_timer_interrupt, | ||
152 | IRQF_TIMER | IRQF_NOBALANCING | | ||
153 | IRQF_TRIGGER_RISING, "gp_timer", evt); | ||
154 | if (err) | ||
155 | pr_err("request_irq failed\n"); | ||
156 | } | ||
154 | 157 | ||
155 | *__this_cpu_ptr(msm_evt.percpu_evt) = evt; | ||
156 | clockevents_config_and_register(evt, GPT_HZ, 4, 0xf0000000); | ||
157 | enable_percpu_irq(evt->irq, IRQ_TYPE_EDGE_RISING); | ||
158 | return 0; | 158 | return 0; |
159 | } | 159 | } |
160 | 160 | ||
@@ -164,11 +164,28 @@ static void msm_local_timer_stop(struct clock_event_device *evt) | |||
164 | disable_percpu_irq(evt->irq); | 164 | disable_percpu_irq(evt->irq); |
165 | } | 165 | } |
166 | 166 | ||
167 | static struct local_timer_ops msm_local_timer_ops = { | 167 | static int msm_timer_cpu_notify(struct notifier_block *self, |
168 | .setup = msm_local_timer_setup, | 168 | unsigned long action, void *hcpu) |
169 | .stop = msm_local_timer_stop, | 169 | { |
170 | /* | ||
171 | * Grab cpu pointer in each case to avoid spurious | ||
172 | * preemptible warnings | ||
173 | */ | ||
174 | switch (action & ~CPU_TASKS_FROZEN) { | ||
175 | case CPU_STARTING: | ||
176 | msm_local_timer_setup(this_cpu_ptr(msm_evt)); | ||
177 | break; | ||
178 | case CPU_DYING: | ||
179 | msm_local_timer_stop(this_cpu_ptr(msm_evt)); | ||
180 | break; | ||
181 | } | ||
182 | |||
183 | return NOTIFY_OK; | ||
184 | } | ||
185 | |||
186 | static struct notifier_block msm_timer_cpu_nb = { | ||
187 | .notifier_call = msm_timer_cpu_notify, | ||
170 | }; | 188 | }; |
171 | #endif /* CONFIG_LOCAL_TIMERS */ | ||
172 | 189 | ||
173 | static notrace u32 msm_sched_clock_read(void) | 190 | static notrace u32 msm_sched_clock_read(void) |
174 | { | 191 | { |
@@ -178,38 +195,35 @@ static notrace u32 msm_sched_clock_read(void) | |||
178 | static void __init msm_timer_init(u32 dgt_hz, int sched_bits, int irq, | 195 | static void __init msm_timer_init(u32 dgt_hz, int sched_bits, int irq, |
179 | bool percpu) | 196 | bool percpu) |
180 | { | 197 | { |
181 | struct clock_event_device *ce = &msm_clockevent; | ||
182 | struct clocksource *cs = &msm_clocksource; | 198 | struct clocksource *cs = &msm_clocksource; |
183 | int res; | 199 | int res = 0; |
200 | |||
201 | msm_timer_irq = irq; | ||
202 | msm_timer_has_ppi = percpu; | ||
203 | |||
204 | msm_evt = alloc_percpu(struct clock_event_device); | ||
205 | if (!msm_evt) { | ||
206 | pr_err("memory allocation failed for clockevents\n"); | ||
207 | goto err; | ||
208 | } | ||
184 | 209 | ||
185 | ce->cpumask = cpumask_of(0); | 210 | if (percpu) |
186 | ce->irq = irq; | 211 | res = request_percpu_irq(irq, msm_timer_interrupt, |
212 | "gp_timer", msm_evt); | ||
187 | 213 | ||
188 | clockevents_config_and_register(ce, GPT_HZ, 4, 0xffffffff); | 214 | if (res) { |
189 | if (percpu) { | 215 | pr_err("request_percpu_irq failed\n"); |
190 | msm_evt.percpu_evt = alloc_percpu(struct clock_event_device *); | 216 | } else { |
191 | if (!msm_evt.percpu_evt) { | 217 | res = register_cpu_notifier(&msm_timer_cpu_nb); |
192 | pr_err("memory allocation failed for %s\n", ce->name); | 218 | if (res) { |
219 | free_percpu_irq(irq, msm_evt); | ||
193 | goto err; | 220 | goto err; |
194 | } | 221 | } |
195 | *__this_cpu_ptr(msm_evt.percpu_evt) = ce; | 222 | |
196 | res = request_percpu_irq(ce->irq, msm_timer_interrupt, | 223 | /* Immediately configure the timer on the boot CPU */ |
197 | ce->name, msm_evt.percpu_evt); | 224 | msm_local_timer_setup(__this_cpu_ptr(msm_evt)); |
198 | if (!res) { | ||
199 | enable_percpu_irq(ce->irq, IRQ_TYPE_EDGE_RISING); | ||
200 | #ifdef CONFIG_LOCAL_TIMERS | ||
201 | local_timer_register(&msm_local_timer_ops); | ||
202 | #endif | ||
203 | } | ||
204 | } else { | ||
205 | msm_evt.evt = ce; | ||
206 | res = request_irq(ce->irq, msm_timer_interrupt, | ||
207 | IRQF_TIMER | IRQF_NOBALANCING | | ||
208 | IRQF_TRIGGER_RISING, ce->name, &msm_evt.evt); | ||
209 | } | 225 | } |
210 | 226 | ||
211 | if (res) | ||
212 | pr_err("request_irq failed for %s\n", ce->name); | ||
213 | err: | 227 | err: |
214 | writel_relaxed(TIMER_ENABLE_EN, source_base + TIMER_ENABLE); | 228 | writel_relaxed(TIMER_ENABLE_EN, source_base + TIMER_ENABLE); |
215 | res = clocksource_register_hz(cs, dgt_hz); | 229 | res = clocksource_register_hz(cs, dgt_hz); |
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 627fa7e41fba..3d6ee149d3d7 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig | |||
@@ -37,9 +37,8 @@ config ARCH_OMAP4 | |||
37 | select CACHE_L2X0 | 37 | select CACHE_L2X0 |
38 | select CPU_V7 | 38 | select CPU_V7 |
39 | select HAVE_ARM_SCU if SMP | 39 | select HAVE_ARM_SCU if SMP |
40 | select HAVE_ARM_TWD if LOCAL_TIMERS | 40 | select HAVE_ARM_TWD if SMP |
41 | select HAVE_SMP | 41 | select HAVE_SMP |
42 | select LOCAL_TIMERS if SMP | ||
43 | select OMAP_INTERCONNECT | 42 | select OMAP_INTERCONNECT |
44 | select PL310_ERRATA_588369 | 43 | select PL310_ERRATA_588369 |
45 | select PL310_ERRATA_727915 | 44 | select PL310_ERRATA_727915 |
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index b37e1fcbad56..8e99ca368e07 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c | |||
@@ -600,7 +600,6 @@ static OMAP_SYS_32K_TIMER_INIT(4, 1, "timer_32k_ck", "ti,timer-alwon", | |||
600 | #endif | 600 | #endif |
601 | 601 | ||
602 | #ifdef CONFIG_ARCH_OMAP4 | 602 | #ifdef CONFIG_ARCH_OMAP4 |
603 | #ifdef CONFIG_LOCAL_TIMERS | ||
604 | static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, OMAP44XX_LOCAL_TWD_BASE, 29); | 603 | static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, OMAP44XX_LOCAL_TWD_BASE, 29); |
605 | void __init omap4_local_timer_init(void) | 604 | void __init omap4_local_timer_init(void) |
606 | { | 605 | { |
@@ -619,12 +618,6 @@ void __init omap4_local_timer_init(void) | |||
619 | pr_err("twd_local_timer_register failed %d\n", err); | 618 | pr_err("twd_local_timer_register failed %d\n", err); |
620 | } | 619 | } |
621 | } | 620 | } |
622 | #else /* CONFIG_LOCAL_TIMERS */ | ||
623 | void __init omap4_local_timer_init(void) | ||
624 | { | ||
625 | omap4_sync32k_timer_init(); | ||
626 | } | ||
627 | #endif /* CONFIG_LOCAL_TIMERS */ | ||
628 | #endif /* CONFIG_ARCH_OMAP4 */ | 621 | #endif /* CONFIG_ARCH_OMAP4 */ |
629 | 622 | ||
630 | #ifdef CONFIG_SOC_OMAP5 | 623 | #ifdef CONFIG_SOC_OMAP5 |
diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig index d210c0f9c2c4..9db2029aa632 100644 --- a/arch/arm/mach-realview/Kconfig +++ b/arch/arm/mach-realview/Kconfig | |||
@@ -13,7 +13,7 @@ config REALVIEW_EB_A9MP | |||
13 | depends on MACH_REALVIEW_EB | 13 | depends on MACH_REALVIEW_EB |
14 | select CPU_V7 | 14 | select CPU_V7 |
15 | select HAVE_ARM_SCU if SMP | 15 | select HAVE_ARM_SCU if SMP |
16 | select HAVE_ARM_TWD if LOCAL_TIMERS | 16 | select HAVE_ARM_TWD if SMP |
17 | select HAVE_SMP | 17 | select HAVE_SMP |
18 | select MIGHT_HAVE_CACHE_L2X0 | 18 | select MIGHT_HAVE_CACHE_L2X0 |
19 | help | 19 | help |
@@ -26,7 +26,7 @@ config REALVIEW_EB_ARM11MP | |||
26 | select ARCH_HAS_BARRIERS if SMP | 26 | select ARCH_HAS_BARRIERS if SMP |
27 | select CPU_V6K | 27 | select CPU_V6K |
28 | select HAVE_ARM_SCU if SMP | 28 | select HAVE_ARM_SCU if SMP |
29 | select HAVE_ARM_TWD if LOCAL_TIMERS | 29 | select HAVE_ARM_TWD if SMP |
30 | select HAVE_SMP | 30 | select HAVE_SMP |
31 | select MIGHT_HAVE_CACHE_L2X0 | 31 | select MIGHT_HAVE_CACHE_L2X0 |
32 | help | 32 | help |
@@ -48,7 +48,7 @@ config MACH_REALVIEW_PB11MP | |||
48 | select ARM_GIC | 48 | select ARM_GIC |
49 | select CPU_V6K | 49 | select CPU_V6K |
50 | select HAVE_ARM_SCU if SMP | 50 | select HAVE_ARM_SCU if SMP |
51 | select HAVE_ARM_TWD if LOCAL_TIMERS | 51 | select HAVE_ARM_TWD if SMP |
52 | select HAVE_PATA_PLATFORM | 52 | select HAVE_PATA_PLATFORM |
53 | select HAVE_SMP | 53 | select HAVE_SMP |
54 | select MIGHT_HAVE_CACHE_L2X0 | 54 | select MIGHT_HAVE_CACHE_L2X0 |
@@ -92,7 +92,7 @@ config MACH_REALVIEW_PBX | |||
92 | select ARCH_SPARSEMEM_ENABLE if CPU_V7 && !REALVIEW_HIGH_PHYS_OFFSET | 92 | select ARCH_SPARSEMEM_ENABLE if CPU_V7 && !REALVIEW_HIGH_PHYS_OFFSET |
93 | select ARM_GIC | 93 | select ARM_GIC |
94 | select HAVE_ARM_SCU if SMP | 94 | select HAVE_ARM_SCU if SMP |
95 | select HAVE_ARM_TWD if LOCAL_TIMERS | 95 | select HAVE_ARM_TWD if SMP |
96 | select HAVE_PATA_PLATFORM | 96 | select HAVE_PATA_PLATFORM |
97 | select HAVE_SMP | 97 | select HAVE_SMP |
98 | select MIGHT_HAVE_CACHE_L2X0 | 98 | select MIGHT_HAVE_CACHE_L2X0 |
diff --git a/arch/arm/mach-spear/Kconfig b/arch/arm/mach-spear/Kconfig index 442917eedff3..df0d59afeb40 100644 --- a/arch/arm/mach-spear/Kconfig +++ b/arch/arm/mach-spear/Kconfig | |||
@@ -23,7 +23,7 @@ config ARCH_SPEAR13XX | |||
23 | select CPU_V7 | 23 | select CPU_V7 |
24 | select GPIO_SPEAR_SPICS | 24 | select GPIO_SPEAR_SPICS |
25 | select HAVE_ARM_SCU if SMP | 25 | select HAVE_ARM_SCU if SMP |
26 | select HAVE_ARM_TWD if LOCAL_TIMERS | 26 | select HAVE_ARM_TWD if SMP |
27 | select HAVE_SMP | 27 | select HAVE_SMP |
28 | select MIGHT_HAVE_CACHE_L2X0 | 28 | select MIGHT_HAVE_CACHE_L2X0 |
29 | select PINCTRL | 29 | select PINCTRL |
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index ef3a8da49b2d..59925cc896fb 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig | |||
@@ -8,7 +8,7 @@ config ARCH_TEGRA | |||
8 | select COMMON_CLK | 8 | select COMMON_CLK |
9 | select GENERIC_CLOCKEVENTS | 9 | select GENERIC_CLOCKEVENTS |
10 | select HAVE_ARM_SCU if SMP | 10 | select HAVE_ARM_SCU if SMP |
11 | select HAVE_ARM_TWD if LOCAL_TIMERS | 11 | select HAVE_ARM_TWD if SMP |
12 | select HAVE_CLK | 12 | select HAVE_CLK |
13 | select HAVE_SMP | 13 | select HAVE_SMP |
14 | select MIGHT_HAVE_CACHE_L2X0 | 14 | select MIGHT_HAVE_CACHE_L2X0 |
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig index b19b07204aaf..99a28d628297 100644 --- a/arch/arm/mach-ux500/Kconfig +++ b/arch/arm/mach-ux500/Kconfig | |||
@@ -8,7 +8,7 @@ config ARCH_U8500 | |||
8 | select CPU_V7 | 8 | select CPU_V7 |
9 | select GENERIC_CLOCKEVENTS | 9 | select GENERIC_CLOCKEVENTS |
10 | select HAVE_ARM_SCU if SMP | 10 | select HAVE_ARM_SCU if SMP |
11 | select HAVE_ARM_TWD if LOCAL_TIMERS | 11 | select HAVE_ARM_TWD if SMP |
12 | select HAVE_SMP | 12 | select HAVE_SMP |
13 | select MIGHT_HAVE_CACHE_L2X0 | 13 | select MIGHT_HAVE_CACHE_L2X0 |
14 | help | 14 | help |
diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig index b8bbabec6310..83c8677bb181 100644 --- a/arch/arm/mach-vexpress/Kconfig +++ b/arch/arm/mach-vexpress/Kconfig | |||
@@ -10,7 +10,7 @@ config ARCH_VEXPRESS | |||
10 | select CPU_V7 | 10 | select CPU_V7 |
11 | select GENERIC_CLOCKEVENTS | 11 | select GENERIC_CLOCKEVENTS |
12 | select HAVE_ARM_SCU if SMP | 12 | select HAVE_ARM_SCU if SMP |
13 | select HAVE_ARM_TWD if LOCAL_TIMERS | 13 | select HAVE_ARM_TWD if SMP |
14 | select HAVE_CLK | 14 | select HAVE_CLK |
15 | select HAVE_PATA_PLATFORM | 15 | select HAVE_PATA_PLATFORM |
16 | select HAVE_SMP | 16 | select HAVE_SMP |
diff --git a/arch/arm/mach-zynq/Kconfig b/arch/arm/mach-zynq/Kconfig index c1d61f281e68..04f8a4a6e755 100644 --- a/arch/arm/mach-zynq/Kconfig +++ b/arch/arm/mach-zynq/Kconfig | |||
@@ -6,7 +6,7 @@ config ARCH_ZYNQ | |||
6 | select CPU_V7 | 6 | select CPU_V7 |
7 | select GENERIC_CLOCKEVENTS | 7 | select GENERIC_CLOCKEVENTS |
8 | select HAVE_ARM_SCU if SMP | 8 | select HAVE_ARM_SCU if SMP |
9 | select HAVE_ARM_TWD if LOCAL_TIMERS | 9 | select HAVE_ARM_TWD if SMP |
10 | select ICST | 10 | select ICST |
11 | select MIGHT_HAVE_CACHE_L2X0 | 11 | select MIGHT_HAVE_CACHE_L2X0 |
12 | select USE_OF | 12 | select USE_OF |