diff options
-rw-r--r-- | arch/x86/platform/uv/uv_nmi.c | 47 |
1 files changed, 46 insertions, 1 deletions
diff --git a/arch/x86/platform/uv/uv_nmi.c b/arch/x86/platform/uv/uv_nmi.c index 9126dfb6dbfc..9b8ac60ad8db 100644 --- a/arch/x86/platform/uv/uv_nmi.c +++ b/arch/x86/platform/uv/uv_nmi.c | |||
@@ -21,7 +21,9 @@ | |||
21 | 21 | ||
22 | #include <linux/cpu.h> | 22 | #include <linux/cpu.h> |
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/kdb.h> | ||
24 | #include <linux/kexec.h> | 25 | #include <linux/kexec.h> |
26 | #include <linux/kgdb.h> | ||
25 | #include <linux/module.h> | 27 | #include <linux/module.h> |
26 | #include <linux/nmi.h> | 28 | #include <linux/nmi.h> |
27 | #include <linux/sched.h> | 29 | #include <linux/sched.h> |
@@ -32,6 +34,7 @@ | |||
32 | #include <asm/kdebug.h> | 34 | #include <asm/kdebug.h> |
33 | #include <asm/local64.h> | 35 | #include <asm/local64.h> |
34 | #include <asm/nmi.h> | 36 | #include <asm/nmi.h> |
37 | #include <asm/traps.h> | ||
35 | #include <asm/uv/uv.h> | 38 | #include <asm/uv/uv.h> |
36 | #include <asm/uv/uv_hub.h> | 39 | #include <asm/uv/uv_hub.h> |
37 | #include <asm/uv/uv_mmrs.h> | 40 | #include <asm/uv/uv_mmrs.h> |
@@ -153,8 +156,9 @@ module_param_named(retry_count, uv_nmi_retry_count, int, 0644); | |||
153 | * "dump" - dump process stack for each cpu | 156 | * "dump" - dump process stack for each cpu |
154 | * "ips" - dump IP info for each cpu | 157 | * "ips" - dump IP info for each cpu |
155 | * "kdump" - do crash dump | 158 | * "kdump" - do crash dump |
159 | * "kdb" - enter KDB/KGDB (default) | ||
156 | */ | 160 | */ |
157 | static char uv_nmi_action[8] = "dump"; | 161 | static char uv_nmi_action[8] = "kdb"; |
158 | module_param_string(action, uv_nmi_action, sizeof(uv_nmi_action), 0644); | 162 | module_param_string(action, uv_nmi_action, sizeof(uv_nmi_action), 0644); |
159 | 163 | ||
160 | static inline bool uv_nmi_action_is(const char *action) | 164 | static inline bool uv_nmi_action_is(const char *action) |
@@ -540,6 +544,43 @@ static inline void uv_nmi_kdump(int cpu, int master, struct pt_regs *regs) | |||
540 | } | 544 | } |
541 | #endif /* !CONFIG_KEXEC */ | 545 | #endif /* !CONFIG_KEXEC */ |
542 | 546 | ||
547 | #ifdef CONFIG_KGDB_KDB | ||
548 | /* Call KDB from NMI handler */ | ||
549 | static void uv_call_kdb(int cpu, struct pt_regs *regs, int master) | ||
550 | { | ||
551 | int ret; | ||
552 | |||
553 | if (master) { | ||
554 | /* call KGDB NMI handler as MASTER */ | ||
555 | ret = kgdb_nmicallin(cpu, X86_TRAP_NMI, regs, | ||
556 | &uv_nmi_slave_continue); | ||
557 | if (ret) { | ||
558 | pr_alert("KDB returned error, is kgdboc set?\n"); | ||
559 | atomic_set(&uv_nmi_slave_continue, SLAVE_EXIT); | ||
560 | } | ||
561 | } else { | ||
562 | /* wait for KGDB signal that it's ready for slaves to enter */ | ||
563 | int sig; | ||
564 | |||
565 | do { | ||
566 | cpu_relax(); | ||
567 | sig = atomic_read(&uv_nmi_slave_continue); | ||
568 | } while (!sig); | ||
569 | |||
570 | /* call KGDB as slave */ | ||
571 | if (sig == SLAVE_CONTINUE) | ||
572 | kgdb_nmicallback(cpu, regs); | ||
573 | } | ||
574 | uv_nmi_sync_exit(master); | ||
575 | } | ||
576 | |||
577 | #else /* !CONFIG_KGDB_KDB */ | ||
578 | static inline void uv_call_kdb(int cpu, struct pt_regs *regs, int master) | ||
579 | { | ||
580 | pr_err("UV: NMI error: KGDB/KDB is not enabled in this kernel\n"); | ||
581 | } | ||
582 | #endif /* !CONFIG_KGDB_KDB */ | ||
583 | |||
543 | /* | 584 | /* |
544 | * UV NMI handler | 585 | * UV NMI handler |
545 | */ | 586 | */ |
@@ -576,6 +617,10 @@ int uv_handle_nmi(unsigned int reason, struct pt_regs *regs) | |||
576 | if (uv_nmi_action_is("ips") || uv_nmi_action_is("dump")) | 617 | if (uv_nmi_action_is("ips") || uv_nmi_action_is("dump")) |
577 | uv_nmi_dump_state(cpu, regs, master); | 618 | uv_nmi_dump_state(cpu, regs, master); |
578 | 619 | ||
620 | /* Call KDB if enabled */ | ||
621 | else if (uv_nmi_action_is("kdb")) | ||
622 | uv_call_kdb(cpu, regs, master); | ||
623 | |||
579 | /* Clear per_cpu "in nmi" flag */ | 624 | /* Clear per_cpu "in nmi" flag */ |
580 | atomic_set(&uv_cpu_nmi.state, UV_NMI_STATE_OUT); | 625 | atomic_set(&uv_cpu_nmi.state, UV_NMI_STATE_OUT); |
581 | 626 | ||