diff options
Diffstat (limited to 'arch/arm/kernel/smp.c')
-rw-r--r-- | arch/arm/kernel/smp.c | 101 |
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 | ||
60 | int __cpuinit __cpu_up(unsigned int cpu) | 61 | int __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 | ||
412 | void show_ipi_list(struct seq_file *p, int prec) | 417 | void show_ipi_list(struct seq_file *p, int prec) |
@@ -447,9 +452,7 @@ static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent); | |||
447 | static void ipi_timer(void) | 452 | static 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 | ||
563 | static cpumask_t backtrace_mask; | ||
564 | static DEFINE_RAW_SPINLOCK(backtrace_lock); | ||
565 | |||
566 | /* "in progress" flag of arch_trigger_all_cpu_backtrace */ | ||
567 | static unsigned long backtrace_flag; | ||
568 | |||
569 | void 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 | */ | ||
604 | static 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: |