xref: /linux/arch/sh/kernel/nmi_debug.c (revision e5c86679d5e864947a52fb31e45a425dea3e7fa9)
1 /*
2  * Copyright (C) 2007 Atmel Corporation
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
8 #include <linux/delay.h>
9 #include <linux/kdebug.h>
10 #include <linux/notifier.h>
11 #include <linux/sched.h>
12 #include <linux/sched/debug.h>
13 #include <linux/hardirq.h>
14 
15 enum nmi_action {
16 	NMI_SHOW_STATE	= 1 << 0,
17 	NMI_SHOW_REGS	= 1 << 1,
18 	NMI_DIE		= 1 << 2,
19 	NMI_DEBOUNCE	= 1 << 3,
20 };
21 
22 static unsigned long nmi_actions;
23 
24 static int nmi_debug_notify(struct notifier_block *self,
25 		unsigned long val, void *data)
26 {
27 	struct die_args *args = data;
28 
29 	if (likely(val != DIE_NMI))
30 		return NOTIFY_DONE;
31 
32 	if (nmi_actions & NMI_SHOW_STATE)
33 		show_state();
34 	if (nmi_actions & NMI_SHOW_REGS)
35 		show_regs(args->regs);
36 	if (nmi_actions & NMI_DEBOUNCE)
37 		mdelay(10);
38 	if (nmi_actions & NMI_DIE)
39 		return NOTIFY_BAD;
40 
41 	return NOTIFY_OK;
42 }
43 
44 static struct notifier_block nmi_debug_nb = {
45 	.notifier_call = nmi_debug_notify,
46 };
47 
48 static int __init nmi_debug_setup(char *str)
49 {
50 	char *p, *sep;
51 
52 	register_die_notifier(&nmi_debug_nb);
53 
54 	if (*str != '=')
55 		return 0;
56 
57 	for (p = str + 1; *p; p = sep + 1) {
58 		sep = strchr(p, ',');
59 		if (sep)
60 			*sep = 0;
61 		if (strcmp(p, "state") == 0)
62 			nmi_actions |= NMI_SHOW_STATE;
63 		else if (strcmp(p, "regs") == 0)
64 			nmi_actions |= NMI_SHOW_REGS;
65 		else if (strcmp(p, "debounce") == 0)
66 			nmi_actions |= NMI_DEBOUNCE;
67 		else if (strcmp(p, "die") == 0)
68 			nmi_actions |= NMI_DIE;
69 		else
70 			printk(KERN_WARNING "NMI: Unrecognized action `%s'\n",
71 				p);
72 		if (!sep)
73 			break;
74 	}
75 
76 	return 0;
77 }
78 __setup("nmi_debug", nmi_debug_setup);
79