[ARM] 4814/1: RealView: Add broadcasting clockevents support for ARM11MPCore
authorCatalin Marinas <catalin.marinas@arm.com>
Mon, 4 Feb 2008 16:30:57 +0000 (17:30 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Mon, 4 Feb 2008 17:52:19 +0000 (17:52 +0000)
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>
arch/arm/Kconfig
arch/arm/kernel/smp.c
arch/arm/mach-realview/Makefile
arch/arm/mach-realview/core.c
arch/arm/mach-realview/localtimer.c
arch/arm/mach-realview/platsmp.c
include/asm-arm/smp.h

index b82828e768ad4570595a99d0f85e3f77c2e55582..a0aeecc33c739434113ee1cc25813d02063fdbba 100644 (file)
@@ -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
index aef6f9ab900ebebe3bd73ee4cbb045b4b601767f..e9dfbab46cb65ef0a6e85d8aa90a9cc0cc0f1522 100644 (file)
@@ -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);
@@ -299,11 +304,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
         */
index 36e76ba937fc031286eeb4fa7acf46b13e37cd64..ca1e390c3c28795f3873bc8249e3eb3c74a8f078 100644 (file)
@@ -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
index 6c68deed84dc1e5eae9d6670c7e5a707a6652b6c..8cabfec31da2769fdac4d17d336095afa55117ba 100644 (file)
@@ -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
index c7bdf04ab094d1f82f2afbb52c204154cf0dfef4..529eb6979e614cab73b9cf61b2d6cc968cc69ea9 100644 (file)
@@ -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>
 #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 */
index fce3596f9950a6aea5d8489d9d674a99759ad7b0..bb5eaa48520d2d595a7529678e69ed1aff34c0ca 100644 (file)
@@ -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
index 1f7c51a1886d524e738613479ee2622d8df61be7..af99636db400e7e8cfbe81956faa1d84f11ebdf2 100644 (file)
@@ -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,16 +120,17 @@ 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)
 {
 }
 
 #endif
 
+/*
+ * Setup a local timer interrupt for a CPU.
+ */
+extern void local_timer_setup(unsigned int cpu);
+
 /*
  * show local interrupt info
  */