[ARM] smp: move core localtimer support out of platform specific files
authorRussell King <rmk@dyn-67.arm.linux.org.uk>
Sun, 17 May 2009 17:58:34 +0000 (18:58 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Sun, 17 May 2009 17:58:34 +0000 (18:58 +0100)
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/Kconfig
arch/arm/include/asm/localtimer.h [new file with mode: 0644]
arch/arm/include/asm/smp.h
arch/arm/kernel/smp.c
arch/arm/mach-realview/localtimer.c
arch/arm/mach-realview/platsmp.c

index e60ec54..ef4f860 100644 (file)
@@ -859,6 +859,7 @@ source "kernel/time/Kconfig"
 config SMP
        bool "Symmetric Multi-Processing (EXPERIMENTAL)"
        depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP)
+       depends on GENERIC_CLOCKEVENTS
        select USE_GENERIC_SMP_HELPERS
        help
          This enables support for systems with more than one CPU. If you have
diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h
new file mode 100644 (file)
index 0000000..3f8c9eb
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *  arch/arm/include/asm/localtimer.h
+ *
+ *  Copyright (C) 2004-2005 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __ASM_ARM_LOCALTIMER_H
+#define __ASM_ARM_LOCALTIMER_H
+
+struct clock_event_device;
+
+/*
+ * Setup a per-cpu timer, whether it be a local timer or dummy broadcast
+ */
+void percpu_timer_setup(void);
+
+/*
+ * Called from assembly, this is the local timer IRQ handler
+ */
+asmlinkage void do_local_timer(struct pt_regs *);
+
+
+#ifdef CONFIG_LOCAL_TIMERS
+/*
+ * Platform provides this to acknowledge a local timer IRQ.
+ * Returns true if the local timer IRQ is to be processed.
+ */
+int local_timer_ack(void);
+
+/*
+ * Stop a local timer interrupt.
+ */
+void local_timer_stop(void);
+
+/*
+ * Setup a local timer interrupt for a CPU.
+ */
+void local_timer_setup(struct clock_event_device *);
+
+#else
+
+static inline void local_timer_stop(void)
+{
+}
+
+#endif
+
+#endif
index 5995935..608f2d5 100644 (file)
@@ -55,11 +55,6 @@ extern void smp_store_cpu_info(unsigned int cpuid);
  */
 extern void smp_cross_call(const struct cpumask *mask);
 
-/*
- * Broadcast a clock event to other CPUs.
- */
-extern void smp_timer_broadcast(const struct cpumask *mask);
-
 /*
  * Boot a secondary CPU, and assign it the specified idle task.
  * This also gives us the initial stack to use for this CPU.
@@ -100,44 +95,9 @@ extern void arch_send_call_function_single_ipi(int cpu);
 extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 #define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask
 
-/*
- * Local timer interrupt handling function (can be IPI'ed).
- */
-extern void local_timer_interrupt(void);
-
-#ifdef CONFIG_LOCAL_TIMERS
-
-/*
- * Stop a local timer interrupt.
- */
-extern void local_timer_stop(void);
-
-/*
- * Platform provides this to acknowledge a local timer IRQ
- */
-extern int local_timer_ack(void);
-
-#else
-
-static inline void local_timer_stop(void)
-{
-}
-
-#endif
-
-/*
- * Setup a local timer interrupt for a CPU.
- */
-extern void local_timer_setup(void);
-
 /*
  * show local interrupt info
  */
 extern void show_local_irqs(struct seq_file *);
 
-/*
- * Called from assembly, this is the local timer IRQ handler
- */
-asmlinkage void do_local_timer(struct pt_regs *);
-
 #endif /* ifndef __ASM_ARM_SMP_H */
index 6014dfd..91130e2 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/smp.h>
 #include <linux/seq_file.h>
 #include <linux/irq.h>
+#include <linux/percpu.h>
+#include <linux/clockchips.h>
 
 #include <asm/atomic.h>
 #include <asm/cacheflush.h>
@@ -32,6 +34,7 @@
 #include <asm/processor.h>
 #include <asm/tlbflush.h>
 #include <asm/ptrace.h>
+#include <asm/localtimer.h>
 
 /*
  * as from 2.5, kernels no longer have an init_tasks structure
@@ -274,9 +277,9 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
        local_fiq_enable();
 
        /*
-        * Setup local timer for this CPU.
+        * Setup the percpu timer for this CPU.
         */
-       local_timer_setup();
+       percpu_timer_setup();
 
        calibrate_delay();
 
@@ -383,10 +386,16 @@ void show_local_irqs(struct seq_file *p)
        seq_putc(p, '\n');
 }
 
+/*
+ * Timer (local or broadcast) support
+ */
+static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent);
+
 static void ipi_timer(void)
 {
+       struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent);
        irq_enter();
-       local_timer_interrupt();
+       evt->event_handler(evt);
        irq_exit();
 }
 
@@ -405,6 +414,42 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs)
 }
 #endif
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+static void smp_timer_broadcast(const struct cpumask *mask)
+{
+       send_ipi_message(mask, IPI_TIMER);
+}
+
+static void broadcast_timer_set_mode(enum clock_event_mode mode,
+       struct clock_event_device *evt)
+{
+}
+
+static void local_timer_setup(struct clock_event_device *evt)
+{
+       evt->name       = "dummy_timer";
+       evt->features   = CLOCK_EVT_FEAT_ONESHOT |
+                         CLOCK_EVT_FEAT_PERIODIC |
+                         CLOCK_EVT_FEAT_DUMMY;
+       evt->rating     = 400;
+       evt->mult       = 1;
+       evt->set_mode   = broadcast_timer_set_mode;
+       evt->broadcast  = smp_timer_broadcast;
+
+       clockevents_register_device(evt);
+}
+#endif
+
+void __cpuinit percpu_timer_setup(void)
+{
+       unsigned int cpu = smp_processor_id();
+       struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
+
+       evt->cpumask = cpumask_of(cpu);
+
+       local_timer_setup(evt);
+}
+
 static DEFINE_SPINLOCK(stop_lock);
 
 /*
@@ -501,11 +546,6 @@ void smp_send_reschedule(int cpu)
        send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
 }
 
-void smp_timer_broadcast(const struct cpumask *mask)
-{
-       send_ipi_message(mask, IPI_TIMER);
-}
-
 void smp_send_stop(void)
 {
        cpumask_t mask = cpu_online_map;
index 1c01d13..cd98e7a 100644 (file)
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
-#include <linux/device.h>
 #include <linux/smp.h>
 #include <linux/jiffies.h>
-#include <linux/percpu.h>
 #include <linux/clockchips.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
 
-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
 
 /* set up by the platform code */
@@ -44,7 +30,7 @@ void __iomem *twd_base;
 static unsigned long mpcore_timer_rate;
 
 static void local_timer_set_mode(enum clock_event_mode mode,
-                                struct clock_event_device *clk)
+                                struct clock_event_device *evt)
 {
        unsigned long ctrl;
 
@@ -140,32 +126,29 @@ static void __cpuinit twd_calibrate_rate(void)
 /*
  * Setup the local clock events for a CPU.
  */
-void __cpuinit local_timer_setup(void)
+void __cpuinit local_timer_setup(struct clock_event_device *evt)
 {
-       unsigned int cpu = smp_processor_id();
-       struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
        unsigned long flags;
 
        twd_calibrate_rate();
 
-       clk->name               = "local_timer";
-       clk->features           = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
-       clk->rating             = 350;
-       clk->set_mode           = local_timer_set_mode;
-       clk->set_next_event     = local_timer_set_next_event;
-       clk->irq                = IRQ_LOCALTIMER;
-       clk->cpumask            = cpumask_of(cpu);
-       clk->shift              = 20;
-       clk->mult               = div_sc(mpcore_timer_rate, NSEC_PER_SEC, clk->shift);
-       clk->max_delta_ns       = clockevent_delta2ns(0xffffffff, clk);
-       clk->min_delta_ns       = clockevent_delta2ns(0xf, clk);
+       evt->name               = "local_timer";
+       evt->features           = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+       evt->rating             = 350;
+       evt->set_mode           = local_timer_set_mode;
+       evt->set_next_event     = local_timer_set_next_event;
+       evt->irq                = IRQ_LOCALTIMER;
+       evt->shift              = 20;
+       evt->mult               = div_sc(mpcore_timer_rate, NSEC_PER_SEC, evt->shift);
+       evt->max_delta_ns       = clockevent_delta2ns(0xffffffff, evt);
+       evt->min_delta_ns       = clockevent_delta2ns(0xf, evt);
 
        /* Make sure our local interrupt controller has this enabled */
        local_irq_save(flags);
        get_irq_chip(IRQ_LOCALTIMER)->unmask(IRQ_LOCALTIMER);
        local_irq_restore(flags);
 
-       clockevents_register_device(clk);
+       clockevents_register_device(evt);
 }
 
 /*
@@ -176,29 +159,4 @@ void __cpuexit local_timer_stop(void)
        __raw_writel(0, twd_base + 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(void)
-{
-       unsigned int cpu = smp_processor_id();
-       struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
-
-       clk->name               = "dummy_timer";
-       clk->features           = CLOCK_EVT_FEAT_ONESHOT |
-                                 CLOCK_EVT_FEAT_PERIODIC |
-                                 CLOCK_EVT_FEAT_DUMMY;
-       clk->rating             = 400;
-       clk->mult               = 1;
-       clk->set_mode           = dummy_timer_set_mode;
-       clk->broadcast          = smp_timer_broadcast;
-       clk->cpumask            = cpumask_of(cpu);
-
-       clockevents_register_device(clk);
-}
-
-#endif /* !CONFIG_LOCAL_TIMERS */
+#endif /* CONFIG_LOCAL_TIMERS */
index 30a9c68..b34d3a5 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/cacheflush.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
+#include <asm/localtimer.h>
 
 #include <mach/board-eb.h>
 #include <mach/board-pb11mp.h>
@@ -217,13 +218,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        if (max_cpus > ncores)
                max_cpus = ncores;
 
-#if defined(CONFIG_LOCAL_TIMERS) || defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
-       /*
-        * Enable the local timer or broadcast device for the boot CPU.
-        */
-       local_timer_setup();
-#endif
-
        /*
         * Initialise the present map, which describes the set of CPUs
         * actually populated at the present time.
@@ -239,6 +233,12 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
         * WFI
         */
        if (max_cpus > 1) {
+               /*
+                * Enable the local timer or broadcast device for the
+                * boot CPU, but only if we have more than one CPU.
+                */
+               percpu_timer_setup();
+
                scu_enable();
                poke_milo();
        }