Loading arch/arm/Kconfig +10 −0 Original line number Diff line number Diff line Loading @@ -356,6 +356,16 @@ config HOTPLUG_CPU Say Y here to experiment with turning CPUs off and on. CPUs can be controlled through /sys/devices/system/cpu. config LOCAL_TIMERS bool "Use local timer interrupts" depends on SMP && n default y help Enable support for local timers on SMP platforms, rather then the legacy IPI broadcast method. Local timers allows the system accounting to be spread across the timer interval, preventing a "thundering herd" at every timer tick. config PREEMPT bool "Preemptible Kernel (EXPERIMENTAL)" depends on EXPERIMENTAL Loading arch/arm/kernel/entry-armv.S +7 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,13 @@ movne r0, sp adrne lr, 1b bne do_IPI #ifdef CONFIG_LOCAL_TIMERS test_for_ltirq r0, r6, r5, lr movne r0, sp adrne lr, 1b bne do_local_timer #endif #endif .endm Loading arch/arm/kernel/irq.c +1 −0 Original line number Diff line number Diff line Loading @@ -264,6 +264,7 @@ int show_interrupts(struct seq_file *p, void *v) #endif #ifdef CONFIG_SMP show_ipi_list(p); show_local_irqs(p); #endif seq_printf(p, "Err: %10lu\n", irq_err_count); } Loading arch/arm/kernel/smp.c +34 −0 Original line number Diff line number Diff line Loading @@ -184,6 +184,11 @@ int __cpuexit __cpu_disable(void) */ migrate_irqs(); /* * Stop the local timer for this CPU. */ local_timer_stop(cpu); /* * Flush user cache and TLB mappings, and then remove this CPU * from the vm mask set of all processes. Loading Loading @@ -289,6 +294,11 @@ asmlinkage void __cpuinit secondary_start_kernel(void) */ cpu_set(cpu, cpu_online_map); /* * Setup local timer for this CPU. */ local_timer_setup(cpu); /* * OK, it's off to the idle thread for us */ Loading Loading @@ -454,6 +464,18 @@ void show_ipi_list(struct seq_file *p) seq_putc(p, '\n'); } void show_local_irqs(struct seq_file *p) { unsigned int cpu; seq_printf(p, "LOC: "); for_each_present_cpu(cpu) seq_printf(p, "%10u ", irq_stat[cpu].local_timer_irqs); seq_putc(p, '\n'); } static void ipi_timer(struct pt_regs *regs) { int user = user_mode(regs); Loading @@ -464,6 +486,18 @@ static void ipi_timer(struct pt_regs *regs) irq_exit(); } #ifdef CONFIG_LOCAL_TIMERS asmlinkage void do_local_timer(struct pt_regs *regs) { int cpu = smp_processor_id(); if (local_timer_ack()) { irq_stat[cpu].local_timer_irqs++; ipi_timer(regs); } } #endif /* * ipi_call_function - handle IPI from smp_call_function() * Loading include/asm-arm/hardirq.h +1 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ typedef struct { unsigned int __softirq_pending; unsigned int local_timer_irqs; } ____cacheline_aligned irq_cpustat_t; #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */ Loading Loading
arch/arm/Kconfig +10 −0 Original line number Diff line number Diff line Loading @@ -356,6 +356,16 @@ config HOTPLUG_CPU Say Y here to experiment with turning CPUs off and on. CPUs can be controlled through /sys/devices/system/cpu. config LOCAL_TIMERS bool "Use local timer interrupts" depends on SMP && n default y help Enable support for local timers on SMP platforms, rather then the legacy IPI broadcast method. Local timers allows the system accounting to be spread across the timer interval, preventing a "thundering herd" at every timer tick. config PREEMPT bool "Preemptible Kernel (EXPERIMENTAL)" depends on EXPERIMENTAL Loading
arch/arm/kernel/entry-armv.S +7 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,13 @@ movne r0, sp adrne lr, 1b bne do_IPI #ifdef CONFIG_LOCAL_TIMERS test_for_ltirq r0, r6, r5, lr movne r0, sp adrne lr, 1b bne do_local_timer #endif #endif .endm Loading
arch/arm/kernel/irq.c +1 −0 Original line number Diff line number Diff line Loading @@ -264,6 +264,7 @@ int show_interrupts(struct seq_file *p, void *v) #endif #ifdef CONFIG_SMP show_ipi_list(p); show_local_irqs(p); #endif seq_printf(p, "Err: %10lu\n", irq_err_count); } Loading
arch/arm/kernel/smp.c +34 −0 Original line number Diff line number Diff line Loading @@ -184,6 +184,11 @@ int __cpuexit __cpu_disable(void) */ migrate_irqs(); /* * Stop the local timer for this CPU. */ local_timer_stop(cpu); /* * Flush user cache and TLB mappings, and then remove this CPU * from the vm mask set of all processes. Loading Loading @@ -289,6 +294,11 @@ asmlinkage void __cpuinit secondary_start_kernel(void) */ cpu_set(cpu, cpu_online_map); /* * Setup local timer for this CPU. */ local_timer_setup(cpu); /* * OK, it's off to the idle thread for us */ Loading Loading @@ -454,6 +464,18 @@ void show_ipi_list(struct seq_file *p) seq_putc(p, '\n'); } void show_local_irqs(struct seq_file *p) { unsigned int cpu; seq_printf(p, "LOC: "); for_each_present_cpu(cpu) seq_printf(p, "%10u ", irq_stat[cpu].local_timer_irqs); seq_putc(p, '\n'); } static void ipi_timer(struct pt_regs *regs) { int user = user_mode(regs); Loading @@ -464,6 +486,18 @@ static void ipi_timer(struct pt_regs *regs) irq_exit(); } #ifdef CONFIG_LOCAL_TIMERS asmlinkage void do_local_timer(struct pt_regs *regs) { int cpu = smp_processor_id(); if (local_timer_ack()) { irq_stat[cpu].local_timer_irqs++; ipi_timer(regs); } } #endif /* * ipi_call_function - handle IPI from smp_call_function() * Loading
include/asm-arm/hardirq.h +1 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ typedef struct { unsigned int __softirq_pending; unsigned int local_timer_irqs; } ____cacheline_aligned irq_cpustat_t; #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */ Loading