diff options
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/smp.c | 16 | ||||
-rw-r--r-- | arch/arm/kernel/smp_twd.c | 47 |
2 files changed, 46 insertions, 17 deletions
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 917ed2fa4e4..a96c08cd612 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -473,20 +473,6 @@ static void ipi_timer(void) irq_exit(); } -#ifdef CONFIG_LOCAL_TIMERS -irqreturn_t percpu_timer_handler(int irq, void *dev_id) -{ - struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent); - - if (local_timer_ack()) { - evt->event_handler(evt); - return IRQ_HANDLED; - } - - return IRQ_NONE; -} -#endif - #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST static void smp_timer_broadcast(const struct cpumask *mask) { @@ -537,7 +523,7 @@ static void percpu_timer_stop(void) unsigned int cpu = smp_processor_id(); struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); - evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); + local_timer_stop(evt); } #endif diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 01c186222f3..a8a6682d6b5 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -19,6 +19,7 @@ #include <linux/io.h> #include <asm/smp_twd.h> +#include <asm/localtimer.h> #include <asm/hardware/gic.h> /* set up by the platform code */ @@ -26,6 +27,8 @@ void __iomem *twd_base; static unsigned long twd_timer_rate; +static struct clock_event_device __percpu **twd_evt; + static void twd_set_mode(enum clock_event_mode mode, struct clock_event_device *clk) { @@ -80,6 +83,12 @@ int twd_timer_ack(void) return 0; } +void twd_timer_stop(struct clock_event_device *clk) +{ + twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk); + disable_percpu_irq(clk->irq); +} + static void __cpuinit twd_calibrate_rate(void) { unsigned long count; @@ -119,11 +128,43 @@ static void __cpuinit twd_calibrate_rate(void) } } +static irqreturn_t twd_handler(int irq, void *dev_id) +{ + struct clock_event_device *evt = *(struct clock_event_device **)dev_id; + + if (twd_timer_ack()) { + evt->event_handler(evt); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + /* * Setup the local clock events for a CPU. */ void __cpuinit twd_timer_setup(struct clock_event_device *clk) { + struct clock_event_device **this_cpu_clk; + + if (!twd_evt) { + int err; + + twd_evt = alloc_percpu(struct clock_event_device *); + if (!twd_evt) { + pr_err("twd: can't allocate memory\n"); + return; + } + + err = request_percpu_irq(clk->irq, twd_handler, + "twd", twd_evt); + if (err) { + pr_err("twd: can't register interrupt %d (%d)\n", + clk->irq, err); + return; + } + } + twd_calibrate_rate(); clk->name = "local_timer"; @@ -137,8 +178,10 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk) clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk); clk->min_delta_ns = clockevent_delta2ns(0xf, clk); + this_cpu_clk = __this_cpu_ptr(twd_evt); + *this_cpu_clk = clk; + clockevents_register_device(clk); - /* Make sure our local interrupt controller has this enabled */ - gic_enable_ppi(clk->irq); + enable_percpu_irq(clk->irq, 0); } |