aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/smp.c')
-rw-r--r--arch/arm/kernel/smp.c81
1 files changed, 71 insertions, 10 deletions
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 511eb0397c1..e895f97ab00 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -53,6 +53,7 @@ enum ipi_msg_type {
53 IPI_CALL_FUNC, 53 IPI_CALL_FUNC,
54 IPI_CALL_FUNC_SINGLE, 54 IPI_CALL_FUNC_SINGLE,
55 IPI_CPU_STOP, 55 IPI_CPU_STOP,
56 IPI_CPU_BACKTRACE,
56}; 57};
57 58
58int __cpuinit __cpu_up(unsigned int cpu) 59int __cpuinit __cpu_up(unsigned int cpu)
@@ -307,17 +308,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
307 */ 308 */
308 platform_secondary_init(cpu); 309 platform_secondary_init(cpu);
309 310
310 /*
311 * Enable local interrupts.
312 */
313 notify_cpu_starting(cpu); 311 notify_cpu_starting(cpu);
314 local_irq_enable();
315 local_fiq_enable();
316
317 /*
318 * Setup the percpu timer for this CPU.
319 */
320 percpu_timer_setup();
321 312
322 calibrate_delay(); 313 calibrate_delay();
323 314
@@ -329,10 +320,23 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
329 * before we continue. 320 * before we continue.
330 */ 321 */
331 set_cpu_online(cpu, true); 322 set_cpu_online(cpu, true);
323
324 /*
325 * Setup the percpu timer for this CPU.
326 */
327 percpu_timer_setup();
328
332 while (!cpu_active(cpu)) 329 while (!cpu_active(cpu))
333 cpu_relax(); 330 cpu_relax();
334 331
335 /* 332 /*
333 * cpu_active bit is set, so it's safe to enable interrupts
334 * now.
335 */
336 local_irq_enable();
337 local_fiq_enable();
338
339 /*
336 * OK, it's off to the idle thread for us 340 * OK, it's off to the idle thread for us
337 */ 341 */
338 cpu_idle(); 342 cpu_idle();
@@ -411,6 +415,7 @@ static const char *ipi_types[NR_IPI] = {
411 S(IPI_CALL_FUNC, "Function call interrupts"), 415 S(IPI_CALL_FUNC, "Function call interrupts"),
412 S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"), 416 S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"),
413 S(IPI_CPU_STOP, "CPU stop interrupts"), 417 S(IPI_CPU_STOP, "CPU stop interrupts"),
418 S(IPI_CPU_BACKTRACE, "CPU backtrace"),
414}; 419};
415 420
416void show_ipi_list(struct seq_file *p, int prec) 421void show_ipi_list(struct seq_file *p, int prec)
@@ -561,6 +566,58 @@ static void ipi_cpu_stop(unsigned int cpu)
561 cpu_relax(); 566 cpu_relax();
562} 567}
563 568
569static cpumask_t backtrace_mask;
570static DEFINE_RAW_SPINLOCK(backtrace_lock);
571
572/* "in progress" flag of arch_trigger_all_cpu_backtrace */
573static unsigned long backtrace_flag;
574
575void smp_send_all_cpu_backtrace(void)
576{
577 unsigned int this_cpu = smp_processor_id();
578 int i;
579
580 if (test_and_set_bit(0, &backtrace_flag))
581 /*
582 * If there is already a trigger_all_cpu_backtrace() in progress
583 * (backtrace_flag == 1), don't output double cpu dump infos.
584 */
585 return;
586
587 cpumask_copy(&backtrace_mask, cpu_online_mask);
588 cpu_clear(this_cpu, backtrace_mask);
589
590 pr_info("Backtrace for cpu %d (current):\n", this_cpu);
591 dump_stack();
592
593 pr_info("\nsending IPI to all other CPUs:\n");
594 smp_cross_call(&backtrace_mask, IPI_CPU_BACKTRACE);
595
596 /* Wait for up to 10 seconds for all other CPUs to do the backtrace */
597 for (i = 0; i < 10 * 1000; i++) {
598 if (cpumask_empty(&backtrace_mask))
599 break;
600 mdelay(1);
601 }
602
603 clear_bit(0, &backtrace_flag);
604 smp_mb__after_clear_bit();
605}
606
607/*
608 * ipi_cpu_backtrace - handle IPI from smp_send_all_cpu_backtrace()
609 */
610static void ipi_cpu_backtrace(unsigned int cpu, struct pt_regs *regs)
611{
612 if (cpu_isset(cpu, backtrace_mask)) {
613 raw_spin_lock(&backtrace_lock);
614 pr_warning("IPI backtrace for cpu %d\n", cpu);
615 show_regs(regs);
616 raw_spin_unlock(&backtrace_lock);
617 cpu_clear(cpu, backtrace_mask);
618 }
619}
620
564/* 621/*
565 * Main handler for inter-processor interrupts 622 * Main handler for inter-processor interrupts
566 */ 623 */
@@ -601,6 +658,10 @@ asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs)
601 irq_exit(); 658 irq_exit();
602 break; 659 break;
603 660
661 case IPI_CPU_BACKTRACE:
662 ipi_cpu_backtrace(cpu, regs);
663 break;
664
604 default: 665 default:
605 printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n", 666 printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
606 cpu, ipinr); 667 cpu, ipinr);