aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/smp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/smp.c')
-rw-r--r--arch/arm/kernel/smp.c56
1 files changed, 48 insertions, 8 deletions
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 6014dfd22af4..91130e218aef 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -22,6 +22,8 @@
22#include <linux/smp.h> 22#include <linux/smp.h>
23#include <linux/seq_file.h> 23#include <linux/seq_file.h>
24#include <linux/irq.h> 24#include <linux/irq.h>
25#include <linux/percpu.h>
26#include <linux/clockchips.h>
25 27
26#include <asm/atomic.h> 28#include <asm/atomic.h>
27#include <asm/cacheflush.h> 29#include <asm/cacheflush.h>
@@ -32,6 +34,7 @@
32#include <asm/processor.h> 34#include <asm/processor.h>
33#include <asm/tlbflush.h> 35#include <asm/tlbflush.h>
34#include <asm/ptrace.h> 36#include <asm/ptrace.h>
37#include <asm/localtimer.h>
35 38
36/* 39/*
37 * as from 2.5, kernels no longer have an init_tasks structure 40 * as from 2.5, kernels no longer have an init_tasks structure
@@ -274,9 +277,9 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
274 local_fiq_enable(); 277 local_fiq_enable();
275 278
276 /* 279 /*
277 * Setup local timer for this CPU. 280 * Setup the percpu timer for this CPU.
278 */ 281 */
279 local_timer_setup(); 282 percpu_timer_setup();
280 283
281 calibrate_delay(); 284 calibrate_delay();
282 285
@@ -383,10 +386,16 @@ void show_local_irqs(struct seq_file *p)
383 seq_putc(p, '\n'); 386 seq_putc(p, '\n');
384} 387}
385 388
389/*
390 * Timer (local or broadcast) support
391 */
392static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent);
393
386static void ipi_timer(void) 394static void ipi_timer(void)
387{ 395{
396 struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent);
388 irq_enter(); 397 irq_enter();
389 local_timer_interrupt(); 398 evt->event_handler(evt);
390 irq_exit(); 399 irq_exit();
391} 400}
392 401
@@ -405,6 +414,42 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs)
405} 414}
406#endif 415#endif
407 416
417#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
418static void smp_timer_broadcast(const struct cpumask *mask)
419{
420 send_ipi_message(mask, IPI_TIMER);
421}
422
423static void broadcast_timer_set_mode(enum clock_event_mode mode,
424 struct clock_event_device *evt)
425{
426}
427
428static void local_timer_setup(struct clock_event_device *evt)
429{
430 evt->name = "dummy_timer";
431 evt->features = CLOCK_EVT_FEAT_ONESHOT |
432 CLOCK_EVT_FEAT_PERIODIC |
433 CLOCK_EVT_FEAT_DUMMY;
434 evt->rating = 400;
435 evt->mult = 1;
436 evt->set_mode = broadcast_timer_set_mode;
437 evt->broadcast = smp_timer_broadcast;
438
439 clockevents_register_device(evt);
440}
441#endif
442
443void __cpuinit percpu_timer_setup(void)
444{
445 unsigned int cpu = smp_processor_id();
446 struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
447
448 evt->cpumask = cpumask_of(cpu);
449
450 local_timer_setup(evt);
451}
452
408static DEFINE_SPINLOCK(stop_lock); 453static DEFINE_SPINLOCK(stop_lock);
409 454
410/* 455/*
@@ -501,11 +546,6 @@ void smp_send_reschedule(int cpu)
501 send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); 546 send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
502} 547}
503 548
504void smp_timer_broadcast(const struct cpumask *mask)
505{
506 send_ipi_message(mask, IPI_TIMER);
507}
508
509void smp_send_stop(void) 549void smp_send_stop(void)
510{ 550{
511 cpumask_t mask = cpu_online_map; 551 cpumask_t mask = cpu_online_map;