aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/smp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/smp.c')
-rw-r--r--arch/arm/kernel/smp.c101
1 files changed, 84 insertions, 17 deletions
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 5a574296ace..a07ca050112 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -27,7 +27,7 @@
27#include <linux/clockchips.h> 27#include <linux/clockchips.h>
28#include <linux/completion.h> 28#include <linux/completion.h>
29 29
30#include <asm/atomic.h> 30#include <linux/atomic.h>
31#include <asm/cacheflush.h> 31#include <asm/cacheflush.h>
32#include <asm/cpu.h> 32#include <asm/cpu.h>
33#include <asm/cputype.h> 33#include <asm/cputype.h>
@@ -55,6 +55,7 @@ enum ipi_msg_type {
55 IPI_CALL_FUNC, 55 IPI_CALL_FUNC,
56 IPI_CALL_FUNC_SINGLE, 56 IPI_CALL_FUNC_SINGLE,
57 IPI_CPU_STOP, 57 IPI_CPU_STOP,
58 IPI_CPU_BACKTRACE,
58}; 59};
59 60
60int __cpuinit __cpu_up(unsigned int cpu) 61int __cpuinit __cpu_up(unsigned int cpu)
@@ -303,17 +304,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
303 */ 304 */
304 platform_secondary_init(cpu); 305 platform_secondary_init(cpu);
305 306
306 /*
307 * Enable local interrupts.
308 */
309 notify_cpu_starting(cpu); 307 notify_cpu_starting(cpu);
310 local_irq_enable();
311 local_fiq_enable();
312
313 /*
314 * Setup the percpu timer for this CPU.
315 */
316 percpu_timer_setup();
317 308
318 calibrate_delay(); 309 calibrate_delay();
319 310
@@ -325,8 +316,14 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
325 * before we continue. 316 * before we continue.
326 */ 317 */
327 set_cpu_online(cpu, true); 318 set_cpu_online(cpu, true);
328 while (!cpu_active(cpu)) 319
329 cpu_relax(); 320 /*
321 * Setup the percpu timer for this CPU.
322 */
323 percpu_timer_setup();
324
325 local_irq_enable();
326 local_fiq_enable();
330 327
331 /* 328 /*
332 * OK, it's off to the idle thread for us 329 * OK, it's off to the idle thread for us
@@ -367,8 +364,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
367 */ 364 */
368 if (max_cpus > ncores) 365 if (max_cpus > ncores)
369 max_cpus = ncores; 366 max_cpus = ncores;
370 367 if (ncores > 1 && max_cpus) {
371 if (max_cpus > 1) {
372 /* 368 /*
373 * Enable the local timer or broadcast device for the 369 * Enable the local timer or broadcast device for the
374 * boot CPU, but only if we have more than one CPU. 370 * boot CPU, but only if we have more than one CPU.
@@ -376,6 +372,14 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
376 percpu_timer_setup(); 372 percpu_timer_setup();
377 373
378 /* 374 /*
375 * Initialise the present map, which describes the set of CPUs
376 * actually populated at the present time. A platform should
377 * re-initialize the map in platform_smp_prepare_cpus() if
378 * present != possible (e.g. physical hotplug).
379 */
380 init_cpu_present(&cpu_possible_map);
381
382 /*
379 * Initialise the SCU if there are more than one CPU 383 * Initialise the SCU if there are more than one CPU
380 * and let them know where to start. 384 * and let them know where to start.
381 */ 385 */
@@ -407,6 +411,7 @@ static const char *ipi_types[NR_IPI] = {
407 S(IPI_CALL_FUNC, "Function call interrupts"), 411 S(IPI_CALL_FUNC, "Function call interrupts"),
408 S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"), 412 S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"),
409 S(IPI_CPU_STOP, "CPU stop interrupts"), 413 S(IPI_CPU_STOP, "CPU stop interrupts"),
414 S(IPI_CPU_BACKTRACE, "CPU backtrace"),
410}; 415};
411 416
412void show_ipi_list(struct seq_file *p, int prec) 417void show_ipi_list(struct seq_file *p, int prec)
@@ -447,9 +452,7 @@ static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent);
447static void ipi_timer(void) 452static void ipi_timer(void)
448{ 453{
449 struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent); 454 struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent);
450 irq_enter();
451 evt->event_handler(evt); 455 evt->event_handler(evt);
452 irq_exit();
453} 456}
454 457
455#ifdef CONFIG_LOCAL_TIMERS 458#ifdef CONFIG_LOCAL_TIMERS
@@ -557,6 +560,58 @@ static void ipi_cpu_stop(unsigned int cpu)
557 cpu_relax(); 560 cpu_relax();
558} 561}
559 562
563static cpumask_t backtrace_mask;
564static DEFINE_RAW_SPINLOCK(backtrace_lock);
565
566/* "in progress" flag of arch_trigger_all_cpu_backtrace */
567static unsigned long backtrace_flag;
568
569void smp_send_all_cpu_backtrace(void)
570{
571 unsigned int this_cpu = smp_processor_id();
572 int i;
573
574 if (test_and_set_bit(0, &backtrace_flag))
575 /*
576 * If there is already a trigger_all_cpu_backtrace() in progress
577 * (backtrace_flag == 1), don't output double cpu dump infos.
578 */
579 return;
580
581 cpumask_copy(&backtrace_mask, cpu_online_mask);
582 cpu_clear(this_cpu, backtrace_mask);
583
584 pr_info("Backtrace for cpu %d (current):\n", this_cpu);
585 dump_stack();
586
587 pr_info("\nsending IPI to all other CPUs:\n");
588 smp_cross_call(&backtrace_mask, IPI_CPU_BACKTRACE);
589
590 /* Wait for up to 10 seconds for all other CPUs to do the backtrace */
591 for (i = 0; i < 10 * 1000; i++) {
592 if (cpumask_empty(&backtrace_mask))
593 break;
594 mdelay(1);
595 }
596
597 clear_bit(0, &backtrace_flag);
598 smp_mb__after_clear_bit();
599}
600
601/*
602 * ipi_cpu_backtrace - handle IPI from smp_send_all_cpu_backtrace()
603 */
604static void ipi_cpu_backtrace(unsigned int cpu, struct pt_regs *regs)
605{
606 if (cpu_isset(cpu, backtrace_mask)) {
607 raw_spin_lock(&backtrace_lock);
608 pr_warning("IPI backtrace for cpu %d\n", cpu);
609 show_regs(regs);
610 raw_spin_unlock(&backtrace_lock);
611 cpu_clear(cpu, backtrace_mask);
612 }
613}
614
560/* 615/*
561 * Main handler for inter-processor interrupts 616 * Main handler for inter-processor interrupts
562 */ 617 */
@@ -570,7 +625,9 @@ asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs)
570 625
571 switch (ipinr) { 626 switch (ipinr) {
572 case IPI_TIMER: 627 case IPI_TIMER:
628 irq_enter();
573 ipi_timer(); 629 ipi_timer();
630 irq_exit();
574 break; 631 break;
575 632
576 case IPI_RESCHEDULE: 633 case IPI_RESCHEDULE:
@@ -580,15 +637,25 @@ asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs)
580 break; 637 break;
581 638
582 case IPI_CALL_FUNC: 639 case IPI_CALL_FUNC:
640 irq_enter();
583 generic_smp_call_function_interrupt(); 641 generic_smp_call_function_interrupt();
642 irq_exit();
584 break; 643 break;
585 644
586 case IPI_CALL_FUNC_SINGLE: 645 case IPI_CALL_FUNC_SINGLE:
646 irq_enter();
587 generic_smp_call_function_single_interrupt(); 647 generic_smp_call_function_single_interrupt();
648 irq_exit();
588 break; 649 break;
589 650
590 case IPI_CPU_STOP: 651 case IPI_CPU_STOP:
652 irq_enter();
591 ipi_cpu_stop(cpu); 653 ipi_cpu_stop(cpu);
654 irq_exit();
655 break;
656
657 case IPI_CPU_BACKTRACE:
658 ipi_cpu_backtrace(cpu, regs);
592 break; 659 break;
593 660
594 default: 661 default: