aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCatalin Marinas <catalin.marinas@arm.com>2008-02-04 11:30:57 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2008-02-04 12:52:19 -0500
commita8655e83fc44ec2b92cbea9f3ff3cc0da05a991c (patch)
tree56bdc711208aca8b514e7366b56c66b9c05ac1be
parent3e459990961db7f3f2dcf21e2b38a7216dfd10dd (diff)
[ARM] 4814/1: RealView: Add broadcasting clockevents support for ARM11MPCore
This patch adds dummy local timers for each CPU so that the board clock device is used to broadcast events to the other CPUs. The patch also adds the declaration for the dummy_timer_setup function (the equivalent of local_timer_setup when CONFIG_LOCAL_TIMERS is not set). Due to the way clockevents work, the dummy timer on the first CPU has to be registered before the board timer. Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/Kconfig5
-rw-r--r--arch/arm/kernel/smp.c10
-rw-r--r--arch/arm/mach-realview/Makefile3
-rw-r--r--arch/arm/mach-realview/core.c10
-rw-r--r--arch/arm/mach-realview/localtimer.c39
-rw-r--r--arch/arm/mach-realview/platsmp.c6
-rw-r--r--include/asm-arm/smp.h13
7 files changed, 69 insertions, 17 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index b82828e768ad..a0aeecc33c73 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -33,6 +33,11 @@ config GENERIC_CLOCKEVENTS
33 bool 33 bool
34 default n 34 default n
35 35
36config GENERIC_CLOCKEVENTS_BROADCAST
37 bool
38 depends on GENERIC_CLOCKEVENTS
39 default y if SMP && !LOCAL_TIMERS
40
36config MMU 41config MMU
37 bool 42 bool
38 default y 43 default y
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index aef6f9ab900e..e9dfbab46cb6 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -290,6 +290,11 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
290 local_irq_enable(); 290 local_irq_enable();
291 local_fiq_enable(); 291 local_fiq_enable();
292 292
293 /*
294 * Setup local timer for this CPU.
295 */
296 local_timer_setup(cpu);
297
293 calibrate_delay(); 298 calibrate_delay();
294 299
295 smp_store_cpu_info(cpu); 300 smp_store_cpu_info(cpu);
@@ -300,11 +305,6 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
300 cpu_set(cpu, cpu_online_map); 305 cpu_set(cpu, cpu_online_map);
301 306
302 /* 307 /*
303 * Setup local timer for this CPU.
304 */
305 local_timer_setup(cpu);
306
307 /*
308 * OK, it's off to the idle thread for us 308 * OK, it's off to the idle thread for us
309 */ 309 */
310 cpu_idle(); 310 cpu_idle();
diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile
index 36e76ba937fc..ca1e390c3c28 100644
--- a/arch/arm/mach-realview/Makefile
+++ b/arch/arm/mach-realview/Makefile
@@ -4,6 +4,5 @@
4 4
5obj-y := core.o clock.o 5obj-y := core.o clock.o
6obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o 6obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o
7obj-$(CONFIG_SMP) += platsmp.o headsmp.o 7obj-$(CONFIG_SMP) += platsmp.o headsmp.o localtimer.o
8obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o 8obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
9obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 6c68deed84dc..8cabfec31da2 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -596,12 +596,20 @@ static void __init realview_clocksource_init(void)
596} 596}
597 597
598/* 598/*
599 * Set up timer interrupt, and return the current time in seconds. 599 * Set up the clock source and clock events devices
600 */ 600 */
601static void __init realview_timer_init(void) 601static void __init realview_timer_init(void)
602{ 602{
603 u32 val; 603 u32 val;
604 604
605#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
606 /*
607 * The dummy clock device has to be registered before the main device
608 * so that the latter will broadcast the clock events
609 */
610 local_timer_setup(smp_processor_id());
611#endif
612
605 /* 613 /*
606 * set clock frequency: 614 * set clock frequency:
607 * REALVIEW_REFCLK is 32KHz 615 * REALVIEW_REFCLK is 32KHz
diff --git a/arch/arm/mach-realview/localtimer.c b/arch/arm/mach-realview/localtimer.c
index c7bdf04ab094..529eb6979e61 100644
--- a/arch/arm/mach-realview/localtimer.c
+++ b/arch/arm/mach-realview/localtimer.c
@@ -14,6 +14,8 @@
14#include <linux/device.h> 14#include <linux/device.h>
15#include <linux/smp.h> 15#include <linux/smp.h>
16#include <linux/jiffies.h> 16#include <linux/jiffies.h>
17#include <linux/percpu.h>
18#include <linux/clockchips.h>
17 19
18#include <asm/mach/time.h> 20#include <asm/mach/time.h>
19#include <asm/hardware/arm_twd.h> 21#include <asm/hardware/arm_twd.h>
@@ -25,6 +27,20 @@
25#define TWD_BASE(cpu) (__io_address(REALVIEW_TWD_BASE) + \ 27#define TWD_BASE(cpu) (__io_address(REALVIEW_TWD_BASE) + \
26 ((cpu) * REALVIEW_TWD_SIZE)) 28 ((cpu) * REALVIEW_TWD_SIZE))
27 29
30static DEFINE_PER_CPU(struct clock_event_device, local_clockevent);
31
32/*
33 * Used on SMP for either the local timer or IPI_TIMER
34 */
35void local_timer_interrupt(void)
36{
37 struct clock_event_device *clk = &__get_cpu_var(local_clockevent);
38
39 clk->event_handler(clk);
40}
41
42#ifdef CONFIG_LOCAL_TIMERS
43
28static unsigned long mpcore_timer_rate; 44static unsigned long mpcore_timer_rate;
29 45
30/* 46/*
@@ -127,3 +143,26 @@ void __cpuexit local_timer_stop(unsigned int cpu)
127{ 143{
128 __raw_writel(0, TWD_BASE(cpu) + TWD_TIMER_CONTROL); 144 __raw_writel(0, TWD_BASE(cpu) + TWD_TIMER_CONTROL);
129} 145}
146
147#else /* CONFIG_LOCAL_TIMERS */
148
149static void dummy_timer_set_mode(enum clock_event_mode mode,
150 struct clock_event_device *clk)
151{
152}
153
154void __cpuinit local_timer_setup(unsigned int cpu)
155{
156 struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
157
158 clk->name = "dummy_timer";
159 clk->features = CLOCK_EVT_FEAT_DUMMY;
160 clk->rating = 200;
161 clk->set_mode = dummy_timer_set_mode;
162 clk->broadcast = smp_timer_broadcast;
163 clk->cpumask = cpumask_of_cpu(cpu);
164
165 clockevents_register_device(clk);
166}
167
168#endif /* !CONFIG_LOCAL_TIMERS */
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
index fce3596f9950..bb5eaa48520d 100644
--- a/arch/arm/mach-realview/platsmp.c
+++ b/arch/arm/mach-realview/platsmp.c
@@ -187,10 +187,14 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
187 if (max_cpus > ncores) 187 if (max_cpus > ncores)
188 max_cpus = ncores; 188 max_cpus = ncores;
189 189
190#ifdef CONFIG_LOCAL_TIMERS
190 /* 191 /*
191 * Enable the local timer for primary CPU 192 * Enable the local timer for primary CPU. If the device is
193 * dummy (!CONFIG_LOCAL_TIMERS), it was already registers in
194 * realview_timer_init
192 */ 195 */
193 local_timer_setup(cpu); 196 local_timer_setup(cpu);
197#endif
194 198
195 /* 199 /*
196 * Initialise the present map, which describes the set of CPUs 200 * Initialise the present map, which describes the set of CPUs
diff --git a/include/asm-arm/smp.h b/include/asm-arm/smp.h
index 1f7c51a1886d..af99636db400 100644
--- a/include/asm-arm/smp.h
+++ b/include/asm-arm/smp.h
@@ -107,10 +107,6 @@ extern void platform_cpu_enable(unsigned int cpu);
107extern void local_timer_interrupt(void); 107extern void local_timer_interrupt(void);
108 108
109#ifdef CONFIG_LOCAL_TIMERS 109#ifdef CONFIG_LOCAL_TIMERS
110/*
111 * Setup a local timer interrupt for a CPU.
112 */
113extern void local_timer_setup(unsigned int cpu);
114 110
115/* 111/*
116 * Stop a local timer interrupt. 112 * Stop a local timer interrupt.
@@ -124,10 +120,6 @@ extern int local_timer_ack(void);
124 120
125#else 121#else
126 122
127static inline void local_timer_setup(unsigned int cpu)
128{
129}
130
131static inline void local_timer_stop(unsigned int cpu) 123static inline void local_timer_stop(unsigned int cpu)
132{ 124{
133} 125}
@@ -135,6 +127,11 @@ static inline void local_timer_stop(unsigned int cpu)
135#endif 127#endif
136 128
137/* 129/*
130 * Setup a local timer interrupt for a CPU.
131 */
132extern void local_timer_setup(unsigned int cpu);
133
134/*
138 * show local interrupt info 135 * show local interrupt info
139 */ 136 */
140extern void show_local_irqs(struct seq_file *); 137extern void show_local_irqs(struct seq_file *);