aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2013-07-23 17:51:34 -0400
committerOlof Johansson <olof@lixom.net>2013-07-23 19:54:15 -0400
commit47dcd3563e45fc5a59bf7f3326ef56087be8bebe (patch)
tree5cebf3d803be1ad0ac8914332da1472cdc0e2652 /arch/arm
parent3b2f64d00c46e1e4e9bd0bb9bb12619adac27a4b (diff)
parent060fd3043e5e3488504b9e70182e188dd9113aea (diff)
Merge tag 'remove-local-timers' of git://git.kernel.org/pub/scm/linux/kernel/git/davidb/linux-msm into next/cleanup
From Stephen Boyd: Now that we have a generic arch hook for broadcast we can remove the local timer API entirely. Doing so will reduce code in ARM core, reduce the architecture dependencies of our timer drivers, and simplify the code because we no longer go through an architecture layer that is essentially a hotplug notifier. * tag 'remove-local-timers' of git://git.kernel.org/pub/scm/linux/kernel/git/davidb/linux-msm: ARM: smp: Remove local timer API clocksource: time-armada-370-xp: Divorce from local timer API clocksource: time-armada-370-xp: Fix sparse warning ARM: msm: Divorce msm_timer from local timer API ARM: PRIMA2: Divorce timer-marco from local timer API ARM: EXYNOS4: Divorce mct from local timer API ARM: OMAP2+: Divorce from local timer API ARM: smp_twd: Divorce smp_twd from local timer API ARM: smp: Remove duplicate dummy timer implementation Resolved a large number of conflicts due to __cpuinit cleanups, etc. Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/Kconfig12
-rw-r--r--arch/arm/include/asm/localtimer.h34
-rw-r--r--arch/arm/kernel/smp.c87
-rw-r--r--arch/arm/kernel/smp_twd.c64
-rw-r--r--arch/arm/mach-highbank/Kconfig2
-rw-r--r--arch/arm/mach-imx/Kconfig3
-rw-r--r--arch/arm/mach-msm/timer.c124
-rw-r--r--arch/arm/mach-omap2/Kconfig3
-rw-r--r--arch/arm/mach-omap2/timer.c7
-rw-r--r--arch/arm/mach-realview/Kconfig8
-rw-r--r--arch/arm/mach-spear/Kconfig2
-rw-r--r--arch/arm/mach-tegra/Kconfig2
-rw-r--r--arch/arm/mach-ux500/Kconfig2
-rw-r--r--arch/arm/mach-vexpress/Kconfig2
-rw-r--r--arch/arm/mach-zynq/Kconfig2
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
1587config 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
15struct clock_event_device;
16
17struct 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 */
26int local_timer_register(struct local_timer_ops *);
27#else
28static 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
149static void percpu_timer_stop(void);
150
151static int platform_cpu_kill(unsigned int cpu) 148static 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
319static 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 */
510static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent);
511
512#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 486#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
513void tick_broadcast(const struct cpumask *mask) 487void 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
519static void broadcast_timer_set_mode(enum clock_event_mode mode,
520 struct clock_event_device *evt)
521{
522}
523
524static 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
537static struct local_timer_ops *lt_ops;
538
539#ifdef CONFIG_LOCAL_TIMERS
540int 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
553static 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 */
570static 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
580static DEFINE_RAW_SPINLOCK(stop_lock); 493static 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 */
30static void __iomem *twd_base; 30static void __iomem *twd_base;
@@ -33,7 +33,7 @@ static struct clk *twd_clk;
33static unsigned long twd_timer_rate; 33static unsigned long twd_timer_rate;
34static DEFINE_PER_CPU(bool, percpu_setup_called); 34static DEFINE_PER_CPU(bool, percpu_setup_called);
35 35
36static struct clock_event_device __percpu **twd_evt; 36static struct clock_event_device __percpu *twd_evt;
37static int twd_ppi; 37static int twd_ppi;
38 38
39static void twd_set_mode(enum clock_event_mode mode, 39static 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
93static void twd_timer_stop(struct clock_event_device *clk) 93static 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
112static int twd_rate_change(struct notifier_block *nb, 114static int twd_rate_change(struct notifier_block *nb,
@@ -132,7 +134,7 @@ static struct notifier_block twd_clk_nb = {
132 134
133static int twd_clk_init(void) 135static 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
157static int twd_cpufreq_transition(struct notifier_block *nb, 159static int twd_cpufreq_transition(struct notifier_block *nb,
@@ -177,7 +179,7 @@ static struct notifier_block twd_cpufreq_nb = {
177 179
178static int twd_cpufreq_init(void) 180static 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
229static irqreturn_t twd_handler(int irq, void *dev_id) 231static 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 */
268static int twd_timer_setup(struct clock_event_device *clk) 270static 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; 309static 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
311static struct local_timer_ops twd_lt_ops = { 324static 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
316static int __init twd_local_timer_common_register(struct device_node *np) 328static 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
340out_irq: 362out_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
50static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) 50static 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
104static struct clock_event_device msm_clockevent = { 104static 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
112static union {
113 struct clock_event_device *evt;
114 struct clock_event_device * __percpu *percpu_evt;
115} msm_evt;
116 105
117static void __iomem *source_base; 106static 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 130static int msm_timer_irq;
131static int msm_timer_has_ppi;
132
142static int msm_local_timer_setup(struct clock_event_device *evt) 133static 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
167static struct local_timer_ops msm_local_timer_ops = { 167static 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
186static struct notifier_block msm_timer_cpu_nb = {
187 .notifier_call = msm_timer_cpu_notify,
170}; 188};
171#endif /* CONFIG_LOCAL_TIMERS */
172 189
173static notrace u32 msm_sched_clock_read(void) 190static notrace u32 msm_sched_clock_read(void)
174{ 191{
@@ -178,38 +195,35 @@ static notrace u32 msm_sched_clock_read(void)
178static void __init msm_timer_init(u32 dgt_hz, int sched_bits, int irq, 195static 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);
213err: 227err:
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
604static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, OMAP44XX_LOCAL_TWD_BASE, 29); 603static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, OMAP44XX_LOCAL_TWD_BASE, 29);
605void __init omap4_local_timer_init(void) 604void __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 */
623void __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