diff options
-rw-r--r-- | arch/x86/include/asm/nmi.h | 2 | ||||
-rw-r--r-- | arch/x86/kernel/nmi.c | 18 | ||||
-rw-r--r-- | drivers/watchdog/hpwdt.c | 27 |
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); | |||
27 | enum { | 27 | enum { |
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); | |||
212 | static notrace __kprobes void | 222 | static notrace __kprobes void |
213 | pci_serr_error(unsigned char reason, struct pt_regs *regs) | 223 | pci_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 | |||
743 | error2: | ||
744 | unregister_nmi_handler(NMI_SERR, "hpwdt"); | ||
745 | error1: | ||
746 | unregister_nmi_handler(NMI_UNKNOWN, "hpwdt"); | ||
747 | error: | ||
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 | ||
743 | static void hpwdt_exit_nmi_decoding(void) | 756 | static void hpwdt_exit_nmi_decoding(void) |