diff options
Diffstat (limited to 'arch')
-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 |
4 files changed, 52 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 | * |