Commit 37ee16ae authored by Russell King's avatar Russell King Committed by Russell King

[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: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 3b6353fa
......@@ -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
......
......@@ -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
......
......@@ -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);
}
......
......@@ -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.
......@@ -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
*/
......@@ -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);
......@@ -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()
*
......
......@@ -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 */
......
......@@ -92,4 +92,42 @@ extern void platform_cpu_die(unsigned int cpu);
extern int platform_cpu_kill(unsigned int cpu);
extern void platform_cpu_enable(unsigned int cpu);
#ifdef CONFIG_LOCAL_TIMERS
/*
* Setup a local timer interrupt for a CPU.
*/
extern void local_timer_setup(unsigned int cpu);
/*
* Stop a local timer interrupt.
*/
extern void local_timer_stop(unsigned int cpu);
/*
* Platform provides this to acknowledge a local timer IRQ
*/
extern int local_timer_ack(void);
#else
static inline void local_timer_setup(unsigned int cpu)
{
}
static inline void local_timer_stop(unsigned int cpu)
{
}
#endif
/*
* show local interrupt info
*/
extern void show_local_irqs(struct seq_file *);
/*
* Called from assembly, this is the local timer IRQ handler
*/
asmlinkage void do_local_timer(struct pt_regs *);
#endif /* ifndef __ASM_ARM_SMP_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment