diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2005-11-08 14:08:05 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2005-11-08 14:08:05 -0500 |
commit | 37ee16ae93a3e4ae7dd51beb81d249f5f12a55c2 (patch) | |
tree | a6cf9773ddb5eae9f173c6a9c9d6120faa5688a4 | |
parent | 3b6353fae0d7ba772d7eb2651727332c9e9c74ac (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/Kconfig | 10 | ||||
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 7 | ||||
-rw-r--r-- | arch/arm/kernel/irq.c | 1 | ||||
-rw-r--r-- | arch/arm/kernel/smp.c | 34 | ||||
-rw-r--r-- | include/asm-arm/hardirq.h | 1 | ||||
-rw-r--r-- | include/asm-arm/smp.h | 38 |
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 | ||
359 | config 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 | |||
359 | config PREEMPT | 369 | config 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 | ||
467 | void 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 | |||
457 | static void ipi_timer(struct pt_regs *regs) | 479 | static 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 | ||
490 | asmlinkage 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 | ||
9 | typedef struct { | 9 | typedef 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); | |||
92 | extern int platform_cpu_kill(unsigned int cpu); | 92 | extern int platform_cpu_kill(unsigned int cpu); |
93 | extern void platform_cpu_enable(unsigned int cpu); | 93 | extern 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 | */ | ||
99 | extern void local_timer_setup(unsigned int cpu); | ||
100 | |||
101 | /* | ||
102 | * Stop a local timer interrupt. | ||
103 | */ | ||
104 | extern void local_timer_stop(unsigned int cpu); | ||
105 | |||
106 | /* | ||
107 | * Platform provides this to acknowledge a local timer IRQ | ||
108 | */ | ||
109 | extern int local_timer_ack(void); | ||
110 | |||
111 | #else | ||
112 | |||
113 | static inline void local_timer_setup(unsigned int cpu) | ||
114 | { | ||
115 | } | ||
116 | |||
117 | static inline void local_timer_stop(unsigned int cpu) | ||
118 | { | ||
119 | } | ||
120 | |||
121 | #endif | ||
122 | |||
123 | /* | ||
124 | * show local interrupt info | ||
125 | */ | ||
126 | extern void show_local_irqs(struct seq_file *); | ||
127 | |||
128 | /* | ||
129 | * Called from assembly, this is the local timer IRQ handler | ||
130 | */ | ||
131 | asmlinkage void do_local_timer(struct pt_regs *); | ||
132 | |||
95 | #endif /* ifndef __ASM_ARM_SMP_H */ | 133 | #endif /* ifndef __ASM_ARM_SMP_H */ |