aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2005-11-08 14:08:05 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2005-11-08 14:08:05 -0500
commit37ee16ae93a3e4ae7dd51beb81d249f5f12a55c2 (patch)
treea6cf9773ddb5eae9f173c6a9c9d6120faa5688a4
parent3b6353fae0d7ba772d7eb2651727332c9e9c74ac (diff)
[ARM SMP] Add core ARM support for local timers
Add infrastructure for supporting per-cpu local timers to update the profiling information and update system time accounting. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/Kconfig10
-rw-r--r--arch/arm/kernel/entry-armv.S7
-rw-r--r--arch/arm/kernel/irq.c1
-rw-r--r--arch/arm/kernel/smp.c34
-rw-r--r--include/asm-arm/hardirq.h1
-rw-r--r--include/asm-arm/smp.h38
6 files changed, 91 insertions, 0 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 91d5ef3397be..3bfef0934c9d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -356,6 +356,16 @@ config HOTPLUG_CPU
356 Say Y here to experiment with turning CPUs off and on. CPUs 356 Say Y here to experiment with turning CPUs off and on. CPUs
357 can be controlled through /sys/devices/system/cpu. 357 can be controlled through /sys/devices/system/cpu.
358 358
359config LOCAL_TIMERS
360 bool "Use local timer interrupts"
361 depends on SMP && n
362 default y
363 help
364 Enable support for local timers on SMP platforms, rather then the
365 legacy IPI broadcast method. Local timers allows the system
366 accounting to be spread across the timer interval, preventing a
367 "thundering herd" at every timer tick.
368
359config PREEMPT 369config PREEMPT
360 bool "Preemptible Kernel (EXPERIMENTAL)" 370 bool "Preemptible Kernel (EXPERIMENTAL)"
361 depends on EXPERIMENTAL 371 depends on EXPERIMENTAL
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index a511ec5b11a3..d9fb819bf7cc 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -47,6 +47,13 @@
47 movne r0, sp 47 movne r0, sp
48 adrne lr, 1b 48 adrne lr, 1b
49 bne do_IPI 49 bne do_IPI
50
51#ifdef CONFIG_LOCAL_TIMERS
52 test_for_ltirq r0, r6, r5, lr
53 movne r0, sp
54 adrne lr, 1b
55 bne do_local_timer
56#endif
50#endif 57#endif
51 58
52 .endm 59 .endm
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 6f86d0af7c56..d7099dbbb879 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -264,6 +264,7 @@ unlock:
264#endif 264#endif
265#ifdef CONFIG_SMP 265#ifdef CONFIG_SMP
266 show_ipi_list(p); 266 show_ipi_list(p);
267 show_local_irqs(p);
267#endif 268#endif
268 seq_printf(p, "Err: %10lu\n", irq_err_count); 269 seq_printf(p, "Err: %10lu\n", irq_err_count);
269 } 270 }
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index f5fc57e0fe41..77e2e9ca89fa 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -185,6 +185,11 @@ int __cpuexit __cpu_disable(void)
185 migrate_irqs(); 185 migrate_irqs();
186 186
187 /* 187 /*
188 * Stop the local timer for this CPU.
189 */
190 local_timer_stop(cpu);
191
192 /*
188 * Flush user cache and TLB mappings, and then remove this CPU 193 * Flush user cache and TLB mappings, and then remove this CPU
189 * from the vm mask set of all processes. 194 * from the vm mask set of all processes.
190 */ 195 */
@@ -290,6 +295,11 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
290 cpu_set(cpu, cpu_online_map); 295 cpu_set(cpu, cpu_online_map);
291 296
292 /* 297 /*
298 * Setup local timer for this CPU.
299 */
300 local_timer_setup(cpu);
301
302 /*
293 * OK, it's off to the idle thread for us 303 * OK, it's off to the idle thread for us
294 */ 304 */
295 cpu_idle(); 305 cpu_idle();
@@ -454,6 +464,18 @@ void show_ipi_list(struct seq_file *p)
454 seq_putc(p, '\n'); 464 seq_putc(p, '\n');
455} 465}
456 466
467void show_local_irqs(struct seq_file *p)
468{
469 unsigned int cpu;
470
471 seq_printf(p, "LOC: ");
472
473 for_each_present_cpu(cpu)
474 seq_printf(p, "%10u ", irq_stat[cpu].local_timer_irqs);
475
476 seq_putc(p, '\n');
477}
478
457static void ipi_timer(struct pt_regs *regs) 479static void ipi_timer(struct pt_regs *regs)
458{ 480{
459 int user = user_mode(regs); 481 int user = user_mode(regs);
@@ -464,6 +486,18 @@ static void ipi_timer(struct pt_regs *regs)
464 irq_exit(); 486 irq_exit();
465} 487}
466 488
489#ifdef CONFIG_LOCAL_TIMERS
490asmlinkage void do_local_timer(struct pt_regs *regs)
491{
492 int cpu = smp_processor_id();
493
494 if (local_timer_ack()) {
495 irq_stat[cpu].local_timer_irqs++;
496 ipi_timer(regs);
497 }
498}
499#endif
500
467/* 501/*
468 * ipi_call_function - handle IPI from smp_call_function() 502 * ipi_call_function - handle IPI from smp_call_function()
469 * 503 *
diff --git a/include/asm-arm/hardirq.h b/include/asm-arm/hardirq.h
index e5ccb6b8ff83..1cbb173bf5b1 100644
--- a/include/asm-arm/hardirq.h
+++ b/include/asm-arm/hardirq.h
@@ -8,6 +8,7 @@
8 8
9typedef struct { 9typedef struct {
10 unsigned int __softirq_pending; 10 unsigned int __softirq_pending;
11 unsigned int local_timer_irqs;
11} ____cacheline_aligned irq_cpustat_t; 12} ____cacheline_aligned irq_cpustat_t;
12 13
13#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */ 14#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
diff --git a/include/asm-arm/smp.h b/include/asm-arm/smp.h
index 52e7c8d830b2..5a72e50ca9fc 100644
--- a/include/asm-arm/smp.h
+++ b/include/asm-arm/smp.h
@@ -92,4 +92,42 @@ extern void platform_cpu_die(unsigned int cpu);
92extern int platform_cpu_kill(unsigned int cpu); 92extern int platform_cpu_kill(unsigned int cpu);
93extern void platform_cpu_enable(unsigned int cpu); 93extern void platform_cpu_enable(unsigned int cpu);
94 94
95#ifdef CONFIG_LOCAL_TIMERS
96/*
97 * Setup a local timer interrupt for a CPU.
98 */
99extern void local_timer_setup(unsigned int cpu);
100
101/*
102 * Stop a local timer interrupt.
103 */
104extern void local_timer_stop(unsigned int cpu);
105
106/*
107 * Platform provides this to acknowledge a local timer IRQ
108 */
109extern int local_timer_ack(void);
110
111#else
112
113static inline void local_timer_setup(unsigned int cpu)
114{
115}
116
117static inline void local_timer_stop(unsigned int cpu)
118{
119}
120
121#endif
122
123/*
124 * show local interrupt info
125 */
126extern void show_local_irqs(struct seq_file *);
127
128/*
129 * Called from assembly, this is the local timer IRQ handler
130 */
131asmlinkage void do_local_timer(struct pt_regs *);
132
95#endif /* ifndef __ASM_ARM_SMP_H */ 133#endif /* ifndef __ASM_ARM_SMP_H */