diff options
Diffstat (limited to 'arch/mips/kernel/gdb-stub.c')
| -rw-r--r-- | arch/mips/kernel/gdb-stub.c | 61 | 
1 files changed, 60 insertions, 1 deletions
| diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c index d4f88e0af24c..6ecbdc1fefd1 100644 --- a/arch/mips/kernel/gdb-stub.c +++ b/arch/mips/kernel/gdb-stub.c | |||
| @@ -140,6 +140,7 @@ | |||
| 140 | #include <asm/system.h> | 140 | #include <asm/system.h> | 
| 141 | #include <asm/gdb-stub.h> | 141 | #include <asm/gdb-stub.h> | 
| 142 | #include <asm/inst.h> | 142 | #include <asm/inst.h> | 
| 143 | #include <asm/smp.h> | ||
| 143 | 144 | ||
| 144 | /* | 145 | /* | 
| 145 | * external low-level support routines | 146 | * external low-level support routines | 
| @@ -669,6 +670,64 @@ static void kgdb_wait(void *arg) | |||
| 669 | local_irq_restore(flags); | 670 | local_irq_restore(flags); | 
| 670 | } | 671 | } | 
| 671 | 672 | ||
| 673 | /* | ||
| 674 | * GDB stub needs to call kgdb_wait on all processor with interrupts | ||
| 675 | * disabled, so it uses it's own special variant. | ||
| 676 | */ | ||
| 677 | static int kgdb_smp_call_kgdb_wait(void) | ||
| 678 | { | ||
| 679 | #ifdef CONFIG_SMP | ||
| 680 | struct call_data_struct data; | ||
| 681 | int i, cpus = num_online_cpus() - 1; | ||
| 682 | int cpu = smp_processor_id(); | ||
| 683 | |||
| 684 | /* | ||
| 685 | * Can die spectacularly if this CPU isn't yet marked online | ||
| 686 | */ | ||
| 687 | BUG_ON(!cpu_online(cpu)); | ||
| 688 | |||
| 689 | if (!cpus) | ||
| 690 | return 0; | ||
| 691 | |||
| 692 | if (spin_is_locked(&smp_call_lock)) { | ||
| 693 | /* | ||
| 694 | * Some other processor is trying to make us do something | ||
| 695 | * but we're not going to respond... give up | ||
| 696 | */ | ||
| 697 | return -1; | ||
| 698 | } | ||
| 699 | |||
| 700 | /* | ||
| 701 | * We will continue here, accepting the fact that | ||
| 702 | * the kernel may deadlock if another CPU attempts | ||
| 703 | * to call smp_call_function now... | ||
| 704 | */ | ||
| 705 | |||
| 706 | data.func = kgdb_wait; | ||
| 707 | data.info = NULL; | ||
| 708 | atomic_set(&data.started, 0); | ||
| 709 | data.wait = 0; | ||
| 710 | |||
| 711 | spin_lock(&smp_call_lock); | ||
| 712 | call_data = &data; | ||
| 713 | mb(); | ||
| 714 | |||
| 715 | /* Send a message to all other CPUs and wait for them to respond */ | ||
| 716 | for (i = 0; i < NR_CPUS; i++) | ||
| 717 | if (cpu_online(i) && i != cpu) | ||
| 718 | core_send_ipi(i, SMP_CALL_FUNCTION); | ||
| 719 | |||
| 720 | /* Wait for response */ | ||
| 721 | /* FIXME: lock-up detection, backtrace on lock-up */ | ||
| 722 | while (atomic_read(&data.started) != cpus) | ||
| 723 | barrier(); | ||
| 724 | |||
| 725 | call_data = NULL; | ||
| 726 | spin_unlock(&smp_call_lock); | ||
| 727 | #endif | ||
| 728 | |||
| 729 | return 0; | ||
| 730 | } | ||
| 672 | 731 | ||
| 673 | /* | 732 | /* | 
| 674 | * This function does all command processing for interfacing to gdb. It | 733 | * This function does all command processing for interfacing to gdb. It | 
| @@ -718,7 +777,7 @@ void handle_exception (struct gdb_regs *regs) | |||
| 718 | /* | 777 | /* | 
| 719 | * force other cpus to enter kgdb | 778 | * force other cpus to enter kgdb | 
| 720 | */ | 779 | */ | 
| 721 | smp_call_function(kgdb_wait, NULL, 0, 0); | 780 | kgdb_smp_call_kgdb_wait(); | 
| 722 | 781 | ||
| 723 | /* | 782 | /* | 
| 724 | * If we're in breakpoint() increment the PC | 783 | * If we're in breakpoint() increment the PC | 
