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 |