aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/debug
diff options
context:
space:
mode:
authorMike Travis <travis@sgi.com>2013-10-02 11:14:18 -0400
committerIngo Molnar <mingo@kernel.org>2013-10-03 12:47:54 -0400
commit8daaa5f8261bffd2f6217a960f9182d0503a5c44 (patch)
tree2792d0b81d4165f234ffa22ea53b9a85d2819724 /kernel/debug
parent8a1f4653f27ffd5d61088cf6b95c39bb13bf6132 (diff)
kdb: Add support for external NMI handler to call KGDB/KDB
This patch adds a kgdb_nmicallin() interface that can be used by external NMI handlers to call the KGDB/KDB handler. The primary need for this is for those types of NMI interrupts where all the CPUs have already received the NMI signal. Therefore no send_IPI(NMI) is required, and in fact it will cause a 2nd unhandled NMI to occur. This generates the "Dazed and Confuzed" messages. Since all the CPUs are getting the NMI at roughly the same time, it's not guaranteed that the first CPU that hits the NMI handler will manage to enter KGDB and set the dbg_master_lock before the slaves start entering. The new argument "send_ready" was added for KGDB to signal the NMI handler to release the slave CPUs for entry into KGDB. Signed-off-by: Mike Travis <travis@sgi.com> Acked-by: Jason Wessel <jason.wessel@windriver.com> Reviewed-by: Dimitri Sivanich <sivanich@sgi.com> Reviewed-by: Hedi Berriche <hedi@sgi.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net> Link: http://lkml.kernel.org/r/20131002151417.928886849@asylum.americas.sgi.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/debug')
-rw-r--r--kernel/debug/debug_core.c32
-rw-r--r--kernel/debug/debug_core.h3
-rw-r--r--kernel/debug/kdb/kdb_debugger.c5
-rw-r--r--kernel/debug/kdb/kdb_main.c3
4 files changed, 40 insertions, 3 deletions
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c
index 0506d447aed2..7d2f35e5df2f 100644
--- a/kernel/debug/debug_core.c
+++ b/kernel/debug/debug_core.c
@@ -575,8 +575,12 @@ return_normal:
575 raw_spin_lock(&dbg_slave_lock); 575 raw_spin_lock(&dbg_slave_lock);
576 576
577#ifdef CONFIG_SMP 577#ifdef CONFIG_SMP
578 /* If send_ready set, slaves are already waiting */
579 if (ks->send_ready)
580 atomic_set(ks->send_ready, 1);
581
578 /* Signal the other CPUs to enter kgdb_wait() */ 582 /* Signal the other CPUs to enter kgdb_wait() */
579 if ((!kgdb_single_step) && kgdb_do_roundup) 583 else if ((!kgdb_single_step) && kgdb_do_roundup)
580 kgdb_roundup_cpus(flags); 584 kgdb_roundup_cpus(flags);
581#endif 585#endif
582 586
@@ -678,11 +682,11 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs)
678 if (arch_kgdb_ops.enable_nmi) 682 if (arch_kgdb_ops.enable_nmi)
679 arch_kgdb_ops.enable_nmi(0); 683 arch_kgdb_ops.enable_nmi(0);
680 684
685 memset(ks, 0, sizeof(struct kgdb_state));
681 ks->cpu = raw_smp_processor_id(); 686 ks->cpu = raw_smp_processor_id();
682 ks->ex_vector = evector; 687 ks->ex_vector = evector;
683 ks->signo = signo; 688 ks->signo = signo;
684 ks->err_code = ecode; 689 ks->err_code = ecode;
685 ks->kgdb_usethreadid = 0;
686 ks->linux_regs = regs; 690 ks->linux_regs = regs;
687 691
688 if (kgdb_reenter_check(ks)) 692 if (kgdb_reenter_check(ks))
@@ -732,6 +736,30 @@ int kgdb_nmicallback(int cpu, void *regs)
732 return 1; 736 return 1;
733} 737}
734 738
739int kgdb_nmicallin(int cpu, int trapnr, void *regs, atomic_t *send_ready)
740{
741#ifdef CONFIG_SMP
742 if (!kgdb_io_ready(0) || !send_ready)
743 return 1;
744
745 if (kgdb_info[cpu].enter_kgdb == 0) {
746 struct kgdb_state kgdb_var;
747 struct kgdb_state *ks = &kgdb_var;
748
749 memset(ks, 0, sizeof(struct kgdb_state));
750 ks->cpu = cpu;
751 ks->ex_vector = trapnr;
752 ks->signo = SIGTRAP;
753 ks->err_code = KGDB_KDB_REASON_SYSTEM_NMI;
754 ks->linux_regs = regs;
755 ks->send_ready = send_ready;
756 kgdb_cpu_enter(ks, regs, DCPU_WANT_MASTER);
757 return 0;
758 }
759#endif
760 return 1;
761}
762
735static void kgdb_console_write(struct console *co, const char *s, 763static void kgdb_console_write(struct console *co, const char *s,
736 unsigned count) 764 unsigned count)
737{ 765{
diff --git a/kernel/debug/debug_core.h b/kernel/debug/debug_core.h
index 2235967e78b0..572aa4f5677c 100644
--- a/kernel/debug/debug_core.h
+++ b/kernel/debug/debug_core.h
@@ -26,6 +26,7 @@ struct kgdb_state {
26 unsigned long threadid; 26 unsigned long threadid;
27 long kgdb_usethreadid; 27 long kgdb_usethreadid;
28 struct pt_regs *linux_regs; 28 struct pt_regs *linux_regs;
29 atomic_t *send_ready;
29}; 30};
30 31
31/* Exception state values */ 32/* Exception state values */
@@ -74,11 +75,13 @@ extern int kdb_stub(struct kgdb_state *ks);
74extern int kdb_parse(const char *cmdstr); 75extern int kdb_parse(const char *cmdstr);
75extern int kdb_common_init_state(struct kgdb_state *ks); 76extern int kdb_common_init_state(struct kgdb_state *ks);
76extern int kdb_common_deinit_state(void); 77extern int kdb_common_deinit_state(void);
78#define KGDB_KDB_REASON_SYSTEM_NMI KDB_REASON_SYSTEM_NMI
77#else /* ! CONFIG_KGDB_KDB */ 79#else /* ! CONFIG_KGDB_KDB */
78static inline int kdb_stub(struct kgdb_state *ks) 80static inline int kdb_stub(struct kgdb_state *ks)
79{ 81{
80 return DBG_PASS_EVENT; 82 return DBG_PASS_EVENT;
81} 83}
84#define KGDB_KDB_REASON_SYSTEM_NMI 0
82#endif /* CONFIG_KGDB_KDB */ 85#endif /* CONFIG_KGDB_KDB */
83 86
84#endif /* _DEBUG_CORE_H_ */ 87#endif /* _DEBUG_CORE_H_ */
diff --git a/kernel/debug/kdb/kdb_debugger.c b/kernel/debug/kdb/kdb_debugger.c
index 328d18ef31e4..8859ca34dcfe 100644
--- a/kernel/debug/kdb/kdb_debugger.c
+++ b/kernel/debug/kdb/kdb_debugger.c
@@ -69,7 +69,10 @@ int kdb_stub(struct kgdb_state *ks)
69 if (atomic_read(&kgdb_setting_breakpoint)) 69 if (atomic_read(&kgdb_setting_breakpoint))
70 reason = KDB_REASON_KEYBOARD; 70 reason = KDB_REASON_KEYBOARD;
71 71
72 if (in_nmi()) 72 if (ks->err_code == KDB_REASON_SYSTEM_NMI && ks->signo == SIGTRAP)
73 reason = KDB_REASON_SYSTEM_NMI;
74
75 else if (in_nmi())
73 reason = KDB_REASON_NMI; 76 reason = KDB_REASON_NMI;
74 77
75 for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++) { 78 for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++) {
diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c
index 00eb8f7fbf41..0b097c8a1e50 100644
--- a/kernel/debug/kdb/kdb_main.c
+++ b/kernel/debug/kdb/kdb_main.c
@@ -1200,6 +1200,9 @@ static int kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs,
1200 instruction_pointer(regs)); 1200 instruction_pointer(regs));
1201 kdb_dumpregs(regs); 1201 kdb_dumpregs(regs);
1202 break; 1202 break;
1203 case KDB_REASON_SYSTEM_NMI:
1204 kdb_printf("due to System NonMaskable Interrupt\n");
1205 break;
1203 case KDB_REASON_NMI: 1206 case KDB_REASON_NMI:
1204 kdb_printf("due to NonMaskable Interrupt @ " 1207 kdb_printf("due to NonMaskable Interrupt @ "
1205 kdb_machreg_fmt "\n", 1208 kdb_machreg_fmt "\n",