aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/nmi.h2
-rw-r--r--arch/x86/kernel/nmi.c18
-rw-r--r--drivers/watchdog/hpwdt.c27
3 files changed, 40 insertions, 7 deletions
diff --git a/arch/x86/include/asm/nmi.h b/arch/x86/include/asm/nmi.h
index fd3f9f18cf3f..07162dfbff84 100644
--- a/arch/x86/include/asm/nmi.h
+++ b/arch/x86/include/asm/nmi.h
@@ -27,6 +27,8 @@ void arch_trigger_all_cpu_backtrace(void);
27enum { 27enum {
28 NMI_LOCAL=0, 28 NMI_LOCAL=0,
29 NMI_UNKNOWN, 29 NMI_UNKNOWN,
30 NMI_SERR,
31 NMI_IO_CHECK,
30 NMI_MAX 32 NMI_MAX
31}; 33};
32 34
diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c
index 47acaf319165..ac9c1b76df96 100644
--- a/arch/x86/kernel/nmi.c
+++ b/arch/x86/kernel/nmi.c
@@ -54,6 +54,14 @@ static struct nmi_desc nmi_desc[NMI_MAX] =
54 .lock = __SPIN_LOCK_UNLOCKED(&nmi_desc[1].lock), 54 .lock = __SPIN_LOCK_UNLOCKED(&nmi_desc[1].lock),
55 .head = LIST_HEAD_INIT(nmi_desc[1].head), 55 .head = LIST_HEAD_INIT(nmi_desc[1].head),
56 }, 56 },
57 {
58 .lock = __SPIN_LOCK_UNLOCKED(&nmi_desc[2].lock),
59 .head = LIST_HEAD_INIT(nmi_desc[2].head),
60 },
61 {
62 .lock = __SPIN_LOCK_UNLOCKED(&nmi_desc[3].lock),
63 .head = LIST_HEAD_INIT(nmi_desc[3].head),
64 },
57 65
58}; 66};
59 67
@@ -120,6 +128,8 @@ static int __setup_nmi(unsigned int type, struct nmiaction *action)
120 * to manage expectations 128 * to manage expectations
121 */ 129 */
122 WARN_ON_ONCE(type == NMI_UNKNOWN && !list_empty(&desc->head)); 130 WARN_ON_ONCE(type == NMI_UNKNOWN && !list_empty(&desc->head));
131 WARN_ON_ONCE(type == NMI_SERR && !list_empty(&desc->head));
132 WARN_ON_ONCE(type == NMI_IO_CHECK && !list_empty(&desc->head));
123 133
124 /* 134 /*
125 * some handlers need to be executed first otherwise a fake 135 * some handlers need to be executed first otherwise a fake
@@ -212,6 +222,10 @@ EXPORT_SYMBOL_GPL(unregister_nmi_handler);
212static notrace __kprobes void 222static notrace __kprobes void
213pci_serr_error(unsigned char reason, struct pt_regs *regs) 223pci_serr_error(unsigned char reason, struct pt_regs *regs)
214{ 224{
225 /* check to see if anyone registered against these types of errors */
226 if (nmi_handle(NMI_SERR, regs, false))
227 return;
228
215 pr_emerg("NMI: PCI system error (SERR) for reason %02x on CPU %d.\n", 229 pr_emerg("NMI: PCI system error (SERR) for reason %02x on CPU %d.\n",
216 reason, smp_processor_id()); 230 reason, smp_processor_id());
217 231
@@ -241,6 +255,10 @@ io_check_error(unsigned char reason, struct pt_regs *regs)
241{ 255{
242 unsigned long i; 256 unsigned long i;
243 257
258 /* check to see if anyone registered against these types of errors */
259 if (nmi_handle(NMI_IO_CHECK, regs, false))
260 return;
261
244 pr_emerg( 262 pr_emerg(
245 "NMI: IOCK error (debug interrupt?) for reason %02x on CPU %d.\n", 263 "NMI: IOCK error (debug interrupt?) for reason %02x on CPU %d.\n",
246 reason, smp_processor_id()); 264 reason, smp_processor_id());
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 4000b8038cac..6e414b501d58 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -725,19 +725,32 @@ static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev)
725 * Only one function can register for NMI_UNKNOWN 725 * Only one function can register for NMI_UNKNOWN
726 */ 726 */
727 retval = register_nmi_handler(NMI_UNKNOWN, hpwdt_pretimeout, 0, "hpwdt"); 727 retval = register_nmi_handler(NMI_UNKNOWN, hpwdt_pretimeout, 0, "hpwdt");
728 if (retval != 0) { 728 if (retval)
729 dev_warn(&dev->dev, 729 goto error;
730 "Unable to register a die notifier (err=%d).\n", 730 retval = register_nmi_handler(NMI_SERR, hpwdt_pretimeout, 0, "hpwdt");
731 retval); 731 if (retval)
732 if (cru_rom_addr) 732 goto error1;
733 iounmap(cru_rom_addr); 733 retval = register_nmi_handler(NMI_IO_CHECK, hpwdt_pretimeout, 0, "hpwdt");
734 } 734 if (retval)
735 goto error2;
735 736
736 dev_info(&dev->dev, 737 dev_info(&dev->dev,
737 "HP Watchdog Timer Driver: NMI decoding initialized" 738 "HP Watchdog Timer Driver: NMI decoding initialized"
738 ", allow kernel dump: %s (default = 0/OFF)\n", 739 ", allow kernel dump: %s (default = 0/OFF)\n",
739 (allow_kdump == 0) ? "OFF" : "ON"); 740 (allow_kdump == 0) ? "OFF" : "ON");
740 return 0; 741 return 0;
742
743error2:
744 unregister_nmi_handler(NMI_SERR, "hpwdt");
745error1:
746 unregister_nmi_handler(NMI_UNKNOWN, "hpwdt");
747error:
748 dev_warn(&dev->dev,
749 "Unable to register a die notifier (err=%d).\n",
750 retval);
751 if (cru_rom_addr)
752 iounmap(cru_rom_addr);
753 return retval;
741} 754}
742 755
743static void hpwdt_exit_nmi_decoding(void) 756static void hpwdt_exit_nmi_decoding(void)