sh: stacktrace/lockdep/irqflags tracing support.

Wire up all of the essentials for lockdep..

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index aa1ebc5..0137320 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -51,6 +51,14 @@
 config ARCH_MAY_HAVE_PC_FDC
 	bool
 
+config STACKTRACE_SUPPORT
+	bool
+	default y
+
+config LOCKDEP_SUPPORT
+	bool
+	default y
+
 source "init/Kconfig"
 
 menu "System type"
diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug
index dcceec9..66a25ef4 100644
--- a/arch/sh/Kconfig.debug
+++ b/arch/sh/Kconfig.debug
@@ -1,5 +1,9 @@
 menu "Kernel hacking"
 
+config TRACE_IRQFLAGS_SUPPORT
+	bool
+	default y
+
 source "lib/Kconfig.debug"
 
 config SH_STANDARD_BIOS
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index 50d54c2..99c7e52 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -21,3 +21,4 @@
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
 obj-$(CONFIG_APM)		+= apm.o
 obj-$(CONFIG_PM)		+= pm.o
+obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
diff --git a/arch/sh/kernel/cpu/sh2/entry.S b/arch/sh/kernel/cpu/sh2/entry.S
index 298d919..34d51b3 100644
--- a/arch/sh/kernel/cpu/sh2/entry.S
+++ b/arch/sh/kernel/cpu/sh2/entry.S
@@ -184,6 +184,11 @@
 	add	r15,r8
 	mov.l	r9,@r8
 	mov	r9,r8
+#ifdef CONFIG_TRACE_IRQFLAGS
+	mov.l	5f, r9
+	jsr	@r9
+	 nop
+#endif
 	sti
 	bra	system_call
 	 nop
@@ -193,6 +198,9 @@
 2:	.long	break_point_trap_software
 3:	.long	NR_syscalls
 4:	.long	sys_call_table
+#ifdef CONFIG_TRACE_IRQFLAGS
+5:	.long	trace_hardirqs_on
+#endif
 
 #if defined(CONFIG_SH_STANDARD_BIOS)
 	/* Unwind the stack and jmp to the debug entry */
@@ -255,6 +263,11 @@
 
 restore_all:
 	cli
+#ifdef CONFIG_TRACE_IRQFLAGS
+	mov.l	3f, r0
+	jsr	@r0
+	 nop
+#endif
 	mov	r15,r0
 	mov.l	$cpu_mode,r2
 	mov	#OFF_SR,r3
@@ -307,6 +320,9 @@
 	.long	__current_thread_info
 $cpu_mode:	
 	.long	__cpu_mode
+#ifdef CONFIG_TRACE_IRQFLAGS
+3:	.long	trace_hardirqs_off
+#endif
 		
 ! common exception handler
 #include "../../entry-common.S"
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index 7ba3dcb..8c0dc27 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -140,7 +140,7 @@
 	mov.l	1f, r0
  	mov.l	@r0, r6		! address
 	mov.l	3f, r0
-	sti
+
 	jmp	@r0
  	 mov	r15, r4		! regs
 
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S
index 8f96d21..29136a3 100644
--- a/arch/sh/kernel/entry-common.S
+++ b/arch/sh/kernel/entry-common.S
@@ -100,6 +100,11 @@
 	.align	2
 ENTRY(exception_error)
 	!
+#ifdef CONFIG_TRACE_IRQFLAGS
+	mov.l	3f, r0
+	jsr	@r0
+	 nop
+#endif
 	sti
 	mov.l	2f, r0
 	jmp	@r0
@@ -109,10 +114,18 @@
 	.align	2
 1:	.long	break_point_trap_software
 2:	.long	do_exception_error
+#ifdef CONFIG_TRACE_IRQFLAGS
+3:	.long	trace_hardirqs_on
+#endif
 
 	.align	2
 ret_from_exception:
 	preempt_stop()
+#ifdef CONFIG_TRACE_IRQFLAGS
+	mov.l	4f, r0
+	jsr	@r0
+	 nop
+#endif
 ENTRY(ret_from_irq)
 	!
 	mov	#OFF_SR, r0
@@ -143,6 +156,11 @@
 	mov.l	1f, r0
 	mov.l	r0, @(TI_PRE_COUNT,r8)
 
+#ifdef CONFIG_TRACE_IRQFLAGS
+	mov.l	3f, r0
+	jsr	@r0
+	 nop
+#endif
 	sti
 	mov.l	2f, r0
 	jsr	@r0
@@ -150,9 +168,15 @@
 	mov	#0, r0
 	mov.l	r0, @(TI_PRE_COUNT,r8)
 	cli
+#ifdef CONFIG_TRACE_IRQFLAGS
+	mov.l	4f, r0
+	jsr	@r0
+	 nop
+#endif
 
 	bra	need_resched
 	 nop
+
 noresched:
 	bra	__restore_all
 	 nop
@@ -160,11 +184,20 @@
 	.align 2
 1:	.long	PREEMPT_ACTIVE
 2:	.long	schedule
+#ifdef CONFIG_TRACE_IRQFLAGS
+3:	.long	trace_hardirqs_on
+4:	.long	trace_hardirqs_off
+#endif
 #endif
 
 ENTRY(resume_userspace)
 	! r8: current_thread_info
 	cli
+#ifdef CONFIG_TRACE_IRQFLAGS
+	mov.l	5f, r0
+	jsr	@r0
+	 nop
+#endif
 	mov.l	@(TI_FLAGS,r8), r0		! current_thread_info->flags
 	tst	#_TIF_WORK_MASK, r0
 	bt/s	__restore_all
@@ -210,6 +243,11 @@
 	jsr	@r1				! schedule
 	 nop
 	cli
+#ifdef CONFIG_TRACE_IRQFLAGS
+	mov.l	5f, r0
+	jsr	@r0
+	 nop
+#endif
 	!
 	mov.l	@(TI_FLAGS,r8), r0		! current_thread_info->flags
 	tst	#_TIF_WORK_MASK, r0
@@ -221,6 +259,10 @@
 1:	.long	schedule
 2:	.long	do_notify_resume
 3:	.long	restore_all
+#ifdef CONFIG_TRACE_IRQFLAGS
+4:	.long	trace_hardirqs_on
+5:	.long	trace_hardirqs_off
+#endif
 
 	.align	2
 syscall_exit_work:
@@ -229,6 +271,11 @@
 	tst	#_TIF_SYSCALL_TRACE, r0
 	bt/s	work_pending
 	 tst	#_TIF_NEED_RESCHED, r0
+#ifdef CONFIG_TRACE_IRQFLAGS
+	mov.l	5f, r0
+	jsr	@r0
+	 nop
+#endif
 	sti
 	! XXX setup arguments...
 	mov.l	4f, r0			! do_syscall_trace
@@ -265,7 +312,7 @@
 	 mov.l	r0, @(OFF_R0,r15)	! Return value
 
 __restore_all:
-	mov.l	1f,r0
+	mov.l	1f, r0
 	jmp	@r0
 	 nop
 
@@ -331,7 +378,13 @@
 	 mov	#OFF_TRA, r9
 	add	r15, r9
 	mov.l	r8, @r9			! set TRA value to tra
+#ifdef CONFIG_TRACE_IRQFLAGS
+	mov.l	5f, r10
+	jsr	@r10
+	 nop
+#endif
 	sti
+
 	!
 	get_current_thread_info r8, r10
 	mov.l	@(TI_FLAGS,r8), r8
@@ -355,6 +408,11 @@
 	!
 syscall_exit:
 	cli
+#ifdef CONFIG_TRACE_IRQFLAGS
+	mov.l	6f, r0
+	jsr	@r0
+	 nop
+#endif
 	!
 	get_current_thread_info r8, r0
 	mov.l	@(TI_FLAGS,r8), r0		! current_thread_info->flags
@@ -369,3 +427,7 @@
 2:	.long	NR_syscalls
 3:	.long	sys_call_table
 4:	.long	do_syscall_trace
+#ifdef CONFIG_TRACE_IRQFLAGS
+5:	.long	trace_hardirqs_on
+6:	.long	trace_hardirqs_off
+#endif
diff --git a/arch/sh/kernel/stacktrace.c b/arch/sh/kernel/stacktrace.c
new file mode 100644
index 0000000..0d5268a
--- /dev/null
+++ b/arch/sh/kernel/stacktrace.c
@@ -0,0 +1,43 @@
+/*
+ * arch/sh/kernel/stacktrace.c
+ *
+ * Stack trace management functions
+ *
+ *  Copyright (C) 2006  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+#include <linux/thread_info.h>
+#include <asm/ptrace.h>
+
+/*
+ * Save stack-backtrace addresses into a stack_trace buffer.
+ */
+void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+{
+	unsigned long *sp;
+
+	if (!task)
+		task = current;
+	if (task == current)
+		sp = (unsigned long *)current_stack_pointer;
+	else
+		sp = (unsigned long *)task->thread.sp;
+
+	while (!kstack_end(sp)) {
+		unsigned long addr = *sp++;
+
+		if (__kernel_text_address(addr)) {
+			if (trace->skip > 0)
+				trace->skip--;
+			else
+				trace->entries[trace->nr_entries++] = addr;
+			if (trace->nr_entries >= trace->max_entries)
+				break;
+		}
+	}
+}
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c
index cfeefc1..716ebf5 100644
--- a/arch/sh/mm/fault.c
+++ b/arch/sh/mm/fault.c
@@ -37,6 +37,9 @@
 	int si_code;
 	siginfo_t info;
 
+	trace_hardirqs_on();
+	local_irq_enable();
+
 #ifdef CONFIG_SH_KGDB
 	if (kgdb_nofault && kgdb_bus_err_hook)
 		kgdb_bus_err_hook();