aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/kernel-parameters.txt2
-rw-r--r--arch/sh/include/asm/kdebug.h1
-rw-r--r--arch/sh/include/asm/system.h2
-rw-r--r--arch/sh/kernel/Makefile7
-rw-r--r--arch/sh/kernel/cpu/sh3/entry.S26
-rw-r--r--arch/sh/kernel/cpu/sh3/ex.S4
-rw-r--r--arch/sh/kernel/irq.c2
-rw-r--r--arch/sh/kernel/nmi_debug.c77
-rw-r--r--arch/sh/kernel/traps.c21
9 files changed, 133 insertions, 9 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 7936b801fe6a..76c355214dc3 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1514,7 +1514,7 @@ and is between 256 and 4096 characters. It is defined in the file
1514 of returning the full 64-bit number. 1514 of returning the full 64-bit number.
1515 The default is to return 64-bit inode numbers. 1515 The default is to return 64-bit inode numbers.
1516 1516
1517 nmi_debug= [KNL,AVR32] Specify one or more actions to take 1517 nmi_debug= [KNL,AVR32,SH] Specify one or more actions to take
1518 when a NMI is triggered. 1518 when a NMI is triggered.
1519 Format: [state][,regs][,debounce][,die] 1519 Format: [state][,regs][,debounce][,die]
1520 1520
diff --git a/arch/sh/include/asm/kdebug.h b/arch/sh/include/asm/kdebug.h
index 0b9f896f203c..985219f9759e 100644
--- a/arch/sh/include/asm/kdebug.h
+++ b/arch/sh/include/asm/kdebug.h
@@ -4,6 +4,7 @@
4/* Grossly misnamed. */ 4/* Grossly misnamed. */
5enum die_val { 5enum die_val {
6 DIE_TRAP, 6 DIE_TRAP,
7 DIE_NMI,
7 DIE_OOPS, 8 DIE_OOPS,
8}; 9};
9 10
diff --git a/arch/sh/include/asm/system.h b/arch/sh/include/asm/system.h
index 6b272238a46e..b5c5acdc8c0e 100644
--- a/arch/sh/include/asm/system.h
+++ b/arch/sh/include/asm/system.h
@@ -169,7 +169,7 @@ BUILD_TRAP_HANDLER(breakpoint);
169BUILD_TRAP_HANDLER(singlestep); 169BUILD_TRAP_HANDLER(singlestep);
170BUILD_TRAP_HANDLER(fpu_error); 170BUILD_TRAP_HANDLER(fpu_error);
171BUILD_TRAP_HANDLER(fpu_state_restore); 171BUILD_TRAP_HANDLER(fpu_state_restore);
172BUILD_TRAP_HANDLER(unwinder); 172BUILD_TRAP_HANDLER(nmi);
173 173
174#ifdef CONFIG_BUG 174#ifdef CONFIG_BUG
175extern void handle_BUG(struct pt_regs *); 175extern void handle_BUG(struct pt_regs *);
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index f37cf02ad9be..a2d0a40f3848 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -10,9 +10,10 @@ CFLAGS_REMOVE_ftrace.o = -pg
10endif 10endif
11 11
12obj-y := debugtraps.o dumpstack.o idle.o io.o io_generic.o irq.o \ 12obj-y := debugtraps.o dumpstack.o idle.o io.o io_generic.o irq.o \
13 machvec.o process_$(BITS).o ptrace_$(BITS).o setup.o \ 13 machvec.o nmi_debug.o process_$(BITS).o ptrace_$(BITS).o \
14 signal_$(BITS).o sys_sh.o sys_sh$(BITS).o syscalls_$(BITS).o \ 14 setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o \
15 time.o topology.o traps.o traps_$(BITS).o unwinder.o 15 syscalls_$(BITS).o time.o topology.o traps.o \
16 traps_$(BITS).o unwinder.o
16 17
17obj-y += cpu/ 18obj-y += cpu/
18obj-$(CONFIG_VSYSCALL) += vsyscall/ 19obj-$(CONFIG_VSYSCALL) += vsyscall/
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index aebd33d18ff7..d1142d365925 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -532,7 +532,33 @@ ENTRY(handle_interrupt)
532 mov.l 2f, r4 532 mov.l 2f, r4
533 mov.l 3f, r9 533 mov.l 3f, r9
534 mov.l @r4, r4 ! pass INTEVT vector as arg0 534 mov.l @r4, r4 ! pass INTEVT vector as arg0
535
536 shlr2 r4
537 shlr r4
538 mov r4, r0 ! save vector->jmp table offset for later
539
540 shlr2 r4 ! vector to IRQ# conversion
541 add #-0x10, r4
542
543 cmp/pz r4 ! is it a valid IRQ?
544 bt 10f
545
546 /*
547 * We got here as a result of taking the INTEVT path for something
548 * that isn't a valid hard IRQ, therefore we bypass the do_IRQ()
549 * path and special case the event dispatch instead. This is the
550 * expected path for the NMI (and any other brilliantly implemented
551 * exception), which effectively wants regular exception dispatch
552 * but is unfortunately reported through INTEVT rather than
553 * EXPEVT. Grr.
554 */
555 mov.l 6f, r9
556 mov.l @(r0, r9), r9
535 jmp @r9 557 jmp @r9
558 mov r15, r8 ! trap handlers take saved regs in r8
559
56010:
561 jmp @r9 ! Off to do_IRQ() we go.
536 mov r15, r5 ! pass saved registers as arg1 562 mov r15, r5 ! pass saved registers as arg1
537 563
538ENTRY(exception_none) 564ENTRY(exception_none)
diff --git a/arch/sh/kernel/cpu/sh3/ex.S b/arch/sh/kernel/cpu/sh3/ex.S
index e5a0de39a2db..46610c35c232 100644
--- a/arch/sh/kernel/cpu/sh3/ex.S
+++ b/arch/sh/kernel/cpu/sh3/ex.S
@@ -48,9 +48,7 @@ ENTRY(exception_handling_table)
48 .long system_call ! Unconditional Trap /* 160 */ 48 .long system_call ! Unconditional Trap /* 160 */
49 .long exception_error ! reserved_instruction (filled by trap_init) /* 180 */ 49 .long exception_error ! reserved_instruction (filled by trap_init) /* 180 */
50 .long exception_error ! illegal_slot_instruction (filled by trap_init) /*1A0*/ 50 .long exception_error ! illegal_slot_instruction (filled by trap_init) /*1A0*/
51ENTRY(nmi_slot) 51 .long nmi_trap_handler /* 1C0 */ ! Allow trap to debugger
52 .long kgdb_handle_exception /* 1C0 */ ! Allow trap to debugger
53ENTRY(user_break_point_trap)
54 .long break_point_trap /* 1E0 */ 52 .long break_point_trap /* 1E0 */
55 53
56 /* 54 /*
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index d1053392e287..60f8af4497c7 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -114,7 +114,7 @@ asmlinkage int do_IRQ(unsigned int irq, struct pt_regs *regs)
114#endif 114#endif
115 115
116 irq_enter(); 116 irq_enter();
117 irq = irq_demux(evt2irq(irq)); 117 irq = irq_demux(irq);
118 118
119#ifdef CONFIG_IRQSTACKS 119#ifdef CONFIG_IRQSTACKS
120 curctx = (union irq_ctx *)current_thread_info(); 120 curctx = (union irq_ctx *)current_thread_info();
diff --git a/arch/sh/kernel/nmi_debug.c b/arch/sh/kernel/nmi_debug.c
new file mode 100644
index 000000000000..ff0abbd1e652
--- /dev/null
+++ b/arch/sh/kernel/nmi_debug.c
@@ -0,0 +1,77 @@
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/hardirq.h>
13
14enum nmi_action {
15 NMI_SHOW_STATE = 1 << 0,
16 NMI_SHOW_REGS = 1 << 1,
17 NMI_DIE = 1 << 2,
18 NMI_DEBOUNCE = 1 << 3,
19};
20
21static unsigned long nmi_actions;
22
23static int nmi_debug_notify(struct notifier_block *self,
24 unsigned long val, void *data)
25{
26 struct die_args *args = data;
27
28 if (likely(val != DIE_NMI))
29 return NOTIFY_DONE;
30
31 if (nmi_actions & NMI_SHOW_STATE)
32 show_state();
33 if (nmi_actions & NMI_SHOW_REGS)
34 show_regs(args->regs);
35 if (nmi_actions & NMI_DEBOUNCE)
36 mdelay(10);
37 if (nmi_actions & NMI_DIE)
38 return NOTIFY_BAD;
39
40 return NOTIFY_OK;
41}
42
43static struct notifier_block nmi_debug_nb = {
44 .notifier_call = nmi_debug_notify,
45};
46
47static int __init nmi_debug_setup(char *str)
48{
49 char *p, *sep;
50
51 register_die_notifier(&nmi_debug_nb);
52
53 if (*str != '=')
54 return 0;
55
56 for (p = str + 1; *p; p = sep + 1) {
57 sep = strchr(p, ',');
58 if (sep)
59 *sep = 0;
60 if (strcmp(p, "state") == 0)
61 nmi_actions |= NMI_SHOW_STATE;
62 else if (strcmp(p, "regs") == 0)
63 nmi_actions |= NMI_SHOW_REGS;
64 else if (strcmp(p, "debounce") == 0)
65 nmi_actions |= NMI_DEBOUNCE;
66 else if (strcmp(p, "die") == 0)
67 nmi_actions |= NMI_DIE;
68 else
69 printk(KERN_WARNING "NMI: Unrecognized action `%s'\n",
70 p);
71 if (!sep)
72 break;
73 }
74
75 return 0;
76}
77__setup("nmi_debug", nmi_debug_setup);
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index f69bd968fcca..a8396f36bd14 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -5,6 +5,7 @@
5#include <linux/signal.h> 5#include <linux/signal.h>
6#include <linux/sched.h> 6#include <linux/sched.h>
7#include <linux/uaccess.h> 7#include <linux/uaccess.h>
8#include <linux/hardirq.h>
8#include <asm/unwinder.h> 9#include <asm/unwinder.h>
9#include <asm/system.h> 10#include <asm/system.h>
10 11
@@ -91,3 +92,23 @@ BUILD_TRAP_HANDLER(bug)
91 92
92 force_sig(SIGTRAP, current); 93 force_sig(SIGTRAP, current);
93} 94}
95
96BUILD_TRAP_HANDLER(nmi)
97{
98 TRAP_HANDLER_DECL;
99
100 nmi_enter();
101
102 switch (notify_die(DIE_NMI, "NMI", regs, 0, vec & 0xff, SIGINT)) {
103 case NOTIFY_OK:
104 case NOTIFY_STOP:
105 break;
106 case NOTIFY_BAD:
107 die("Fatal Non-Maskable Interrupt", regs, SIGINT);
108 default:
109 printk(KERN_ALERT "Got NMI, but nobody cared. Ignoring...\n");
110 break;
111 }
112
113 nmi_exit();
114}