summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
bool
default n
+config GENERIC_CLOCKEVENTS_BROADCAST
+ bool
+ depends on GENERIC_CLOCKEVENTS
+ default y if SMP && !LOCAL_TIMERS
+
config MMU
bool
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)
local_irq_enable();
local_fiq_enable();
+ /*
+ * Setup local timer for this CPU.
+ */
+ local_timer_setup(cpu);
+
calibrate_delay();
smp_store_cpu_info(cpu);
@@ -300,11 +305,6 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
cpu_set(cpu, cpu_online_map);
/*
- * Setup local timer for this CPU.
- */
- local_timer_setup(cpu);
-
- /*
* OK, it's off to the idle thread for us
*/
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 @@
obj-y := core.o clock.o
obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o
-obj-$(CONFIG_SMP) += platsmp.o headsmp.o
+obj-$(CONFIG_SMP) += platsmp.o headsmp.o localtimer.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
-obj-$(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)
}
/*
- * Set up timer interrupt, and return the current time in seconds.
+ * Set up the clock source and clock events devices
*/
static void __init realview_timer_init(void)
{
u32 val;
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+ /*
+ * The dummy clock device has to be registered before the main device
+ * so that the latter will broadcast the clock events
+ */
+ local_timer_setup(smp_processor_id());
+#endif
+
/*
* set clock frequency:
* 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 @@
#include <linux/device.h>
#include <linux/smp.h>
#include <linux/jiffies.h>
+#include <linux/percpu.h>
+#include <linux/clockchips.h>
#include <asm/mach/time.h>
#include <asm/hardware/arm_twd.h>
@@ -25,6 +27,20 @@
#define TWD_BASE(cpu) (__io_address(REALVIEW_TWD_BASE) + \
((cpu) * REALVIEW_TWD_SIZE))
+static DEFINE_PER_CPU(struct clock_event_device, local_clockevent);
+
+/*
+ * Used on SMP for either the local timer or IPI_TIMER
+ */
+void local_timer_interrupt(void)
+{
+ struct clock_event_device *clk = &__get_cpu_var(local_clockevent);
+
+ clk->event_handler(clk);
+}
+
+#ifdef CONFIG_LOCAL_TIMERS
+
static unsigned long mpcore_timer_rate;
/*
@@ -127,3 +143,26 @@ void __cpuexit local_timer_stop(unsigned int cpu)
{
__raw_writel(0, TWD_BASE(cpu) + TWD_TIMER_CONTROL);
}
+
+#else /* CONFIG_LOCAL_TIMERS */
+
+static void dummy_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *clk)
+{
+}
+
+void __cpuinit local_timer_setup(unsigned int cpu)
+{
+ struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
+
+ clk->name = "dummy_timer";
+ clk->features = CLOCK_EVT_FEAT_DUMMY;
+ clk->rating = 200;
+ clk->set_mode = dummy_timer_set_mode;
+ clk->broadcast = smp_timer_broadcast;
+ clk->cpumask = cpumask_of_cpu(cpu);
+
+ clockevents_register_device(clk);
+}
+
+#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)
if (max_cpus > ncores)
max_cpus = ncores;
+#ifdef CONFIG_LOCAL_TIMERS
/*
- * Enable the local timer for primary CPU
+ * Enable the local timer for primary CPU. If the device is
+ * dummy (!CONFIG_LOCAL_TIMERS), it was already registers in
+ * realview_timer_init
*/
local_timer_setup(cpu);
+#endif
/*
* 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);
extern void local_timer_interrupt(void);
#ifdef CONFIG_LOCAL_TIMERS
-/*
- * Setup a local timer interrupt for a CPU.
- */
-extern void local_timer_setup(unsigned int cpu);
/*
* Stop a local timer interrupt.
@@ -124,10 +120,6 @@ extern int local_timer_ack(void);
#else
-static inline void local_timer_setup(unsigned int cpu)
-{
-}
-
static inline void local_timer_stop(unsigned int cpu)
{
}
@@ -135,6 +127,11 @@ static inline void local_timer_stop(unsigned int cpu)
#endif
/*
+ * Setup a local timer interrupt for a CPU.
+ */
+extern void local_timer_setup(unsigned int cpu);
+
+/*
* show local interrupt info
*/
extern void show_local_irqs(struct seq_file *);