Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Russell King and committed by
Russell King
37ee16ae 3b6353fa

+91
+10
arch/arm/Kconfig
··· 356 356 Say Y here to experiment with turning CPUs off and on. CPUs 357 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 369 config PREEMPT 360 370 bool "Preemptible Kernel (EXPERIMENTAL)" 361 371 depends on EXPERIMENTAL
+7
arch/arm/kernel/entry-armv.S
··· 47 47 movne r0, sp 48 48 adrne lr, 1b 49 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 57 #endif 51 58 52 59 .endm
+1
arch/arm/kernel/irq.c
··· 264 264 #endif 265 265 #ifdef CONFIG_SMP 266 266 show_ipi_list(p); 267 + show_local_irqs(p); 267 268 #endif 268 269 seq_printf(p, "Err: %10lu\n", irq_err_count); 269 270 }
+34
arch/arm/kernel/smp.c
··· 185 185 migrate_irqs(); 186 186 187 187 /* 188 + * Stop the local timer for this CPU. 189 + */ 190 + local_timer_stop(cpu); 191 + 192 + /* 188 193 * Flush user cache and TLB mappings, and then remove this CPU 189 194 * from the vm mask set of all processes. 190 195 */ ··· 293 288 * OK, now it's safe to let the boot CPU continue 294 289 */ 295 290 cpu_set(cpu, cpu_online_map); 291 + 292 + /* 293 + * Setup local timer for this CPU. 294 + */ 295 + local_timer_setup(cpu); 296 296 297 297 /* 298 298 * OK, it's off to the idle thread for us ··· 464 454 seq_putc(p, '\n'); 465 455 } 466 456 457 + void show_local_irqs(struct seq_file *p) 458 + { 459 + unsigned int cpu; 460 + 461 + seq_printf(p, "LOC: "); 462 + 463 + for_each_present_cpu(cpu) 464 + seq_printf(p, "%10u ", irq_stat[cpu].local_timer_irqs); 465 + 466 + seq_putc(p, '\n'); 467 + } 468 + 467 469 static void ipi_timer(struct pt_regs *regs) 468 470 { 469 471 int user = user_mode(regs); ··· 485 463 update_process_times(user); 486 464 irq_exit(); 487 465 } 466 + 467 + #ifdef CONFIG_LOCAL_TIMERS 468 + asmlinkage void do_local_timer(struct pt_regs *regs) 469 + { 470 + int cpu = smp_processor_id(); 471 + 472 + if (local_timer_ack()) { 473 + irq_stat[cpu].local_timer_irqs++; 474 + ipi_timer(regs); 475 + } 476 + } 477 + #endif 488 478 489 479 /* 490 480 * ipi_call_function - handle IPI from smp_call_function()
+1
include/asm-arm/hardirq.h
··· 8 8 9 9 typedef struct { 10 10 unsigned int __softirq_pending; 11 + unsigned int local_timer_irqs; 11 12 } ____cacheline_aligned irq_cpustat_t; 12 13 13 14 #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+38
include/asm-arm/smp.h
··· 92 92 extern int platform_cpu_kill(unsigned int cpu); 93 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 133 #endif /* ifndef __ASM_ARM_SMP_H */