[SPARC64]: Add irqtrace/stacktrace/lockdep support.

Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index e1eabeb..eff0c01 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -14,6 +14,7 @@
 		   power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \
 		   visemul.o prom.o of_device.o
 
+obj-$(CONFIG_STACKTRACE) += stacktrace.o
 obj-$(CONFIG_PCI)	 += ebus.o isa.o pci_common.o pci_iommu.o \
 			    pci_psycho.o pci_sabre.o pci_schizo.o \
 			    pci_sun4v.o pci_sun4v_asm.o
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 6f28bec..c15a3ed 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -597,7 +597,12 @@
 1:	ba,pt		%xcc, etrap_irq
 	 rd		%pc, %g7
 
-2:	mov		%l4, %o1
+2:
+#ifdef CONFIG_TRACE_IRQFLAGS
+	call	trace_hardirqs_off
+	 nop
+#endif
+	mov		%l4, %o1
 	mov		%l5, %o2
 	call		spitfire_access_error
 	 add		%sp, PTREGS_OFF, %o0
@@ -824,6 +829,10 @@
 	wrpr		%g0, 15, %pil
 	ba,pt		%xcc, etrap_irq
 	 rd		%pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+	call		trace_hardirqs_off
+	 nop
+#endif
 	mov		0x0, %o0
 	call		cheetah_plus_parity_error
 	 add		%sp, PTREGS_OFF, %o1
@@ -855,6 +864,10 @@
 	wrpr		%g0, 15, %pil
 	ba,pt		%xcc, etrap_irq
 	 rd		%pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+	call		trace_hardirqs_off
+	 nop
+#endif
 	mov		0x1, %o0
 	call		cheetah_plus_parity_error
 	 add		%sp, PTREGS_OFF, %o1
@@ -1183,6 +1196,10 @@
 	wrpr		%g0, 15, %pil
 	ba,pt		%xcc, etrap_irq
 	 rd		%pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+	call		trace_hardirqs_off
+	 nop
+#endif
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		cheetah_fecc_handler
@@ -1211,6 +1228,10 @@
 	wrpr		%g0, 15, %pil
 	ba,pt		%xcc, etrap_irq
 	 rd		%pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+	call		trace_hardirqs_off
+	 nop
+#endif
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		cheetah_cee_handler
@@ -1239,6 +1260,10 @@
 	wrpr		%g0, 15, %pil
 	ba,pt		%xcc, etrap_irq
 	 rd		%pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+	call		trace_hardirqs_off
+	 nop
+#endif
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		cheetah_deferred_handler
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index c8e9dc9..03ffaf8 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -489,6 +489,14 @@
 	call	__bzero
 	 sub	%o1, %o0, %o1
 
+#ifdef CONFIG_LOCKDEP
+	/* We have this call this super early, as even prom_init can grab
+	 * spinlocks and thus call into the lockdep code.
+	 */
+	call	lockdep_init
+	 nop
+#endif
+
 	mov	%l6, %o1			! OpenPROM stack
 	call	prom_init
 	 mov	%l7, %o0			! OpenPROM cif handler
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
index 3522cd6..079d18a 100644
--- a/arch/sparc64/kernel/rtrap.S
+++ b/arch/sparc64/kernel/rtrap.S
@@ -165,14 +165,26 @@
 __handle_softirq_continue:
 rtrap_xcall:
 		sethi			%hi(0xf << 20), %l4
-		andcc			%l1, TSTATE_PRIV, %l3
 		and			%l1, %l4, %l4
+		andn			%l1, %l4, %l1
+		srl			%l4, 20, %l4
+#ifdef CONFIG_TRACE_IRQFLAGS
+		brnz,pn			%l4, rtrap_no_irq_enable
+		 nop
+		call			trace_hardirqs_on
+		 nop
+		wrpr			%l4, %pil
+rtrap_no_irq_enable:
+#endif
+		andcc			%l1, TSTATE_PRIV, %l3
 		bne,pn			%icc, to_kernel
-		 andn			%l1, %l4, %l1
+		 nop
 
 		/* We must hold IRQs off and atomically test schedule+signal
 		 * state, then hold them off all the way back to userspace.
-		 * If we are returning to kernel, none of this matters.
+		 * If we are returning to kernel, none of this matters.  Note
+		 * that we are disabling interrupts via PSTATE_IE, not using
+		 * %pil.
 		 *
 		 * If we do not do this, there is a window where we would do
 		 * the tests, later the signal/resched event arrives but we do
@@ -256,7 +268,6 @@
 
 		ld			[%sp + PTREGS_OFF + PT_V9_Y], %o3
 		wr			%o3, %g0, %y
-		srl			%l4, 20, %l4
 		wrpr			%l4, 0x0, %pil
 		wrpr			%g0, 0x1, %tl
 		wrpr			%l1, %g0, %tstate
@@ -374,8 +385,8 @@
 		 ldx			[%g6 + TI_FLAGS], %l5
 		andcc			%l5, _TIF_NEED_RESCHED, %g0
 		be,pt			%xcc, kern_fpucheck
-		 srl			%l4, 20, %l5
-		cmp			%l5, 0
+		 nop
+		cmp			%l4, 0
 		bne,pn			%xcc, kern_fpucheck
 		 sethi			%hi(PREEMPT_ACTIVE), %l6
 		stw			%l6, [%g6 + TI_PRE_COUNT]
diff --git a/arch/sparc64/kernel/stacktrace.c b/arch/sparc64/kernel/stacktrace.c
new file mode 100644
index 0000000..c4d15f2
--- /dev/null
+++ b/arch/sparc64/kernel/stacktrace.c
@@ -0,0 +1,41 @@
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+#include <linux/thread_info.h>
+#include <asm/ptrace.h>
+
+void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+{
+	unsigned long ksp, fp, thread_base;
+	struct thread_info *tp;
+
+	if (!task)
+		task = current;
+	tp = task_thread_info(task);
+	if (task == current) {
+		flushw_all();
+		__asm__ __volatile__(
+			"mov	%%fp, %0"
+			: "=r" (ksp)
+		);
+	} else
+		ksp = tp->ksp;
+
+	fp = ksp + STACK_BIAS;
+	thread_base = (unsigned long) tp;
+	do {
+		struct reg_window *rw;
+
+		/* Bogus frame pointer? */
+		if (fp < (thread_base + sizeof(struct thread_info)) ||
+		    fp >= (thread_base + THREAD_SIZE))
+			break;
+
+		rw = (struct reg_window *) fp;
+		if (trace->skip > 0)
+			trace->skip--;
+		else
+			trace->entries[trace->nr_entries++] = rw->ins[7];
+
+		fp = rw->ins[6] + STACK_BIAS;
+	} while (trace->nr_entries < trace->max_entries);
+}
diff --git a/arch/sparc64/kernel/sun4v_ivec.S b/arch/sparc64/kernel/sun4v_ivec.S
index 49703c3..405855d 100644
--- a/arch/sparc64/kernel/sun4v_ivec.S
+++ b/arch/sparc64/kernel/sun4v_ivec.S
@@ -190,7 +190,10 @@
 	mov	%g1, %g4
 	ba,pt	%xcc, etrap_irq
 	 rd	%pc, %g7
-
+#ifdef CONFIG_TRACE_IRQFLAGS
+	call		trace_hardirqs_off
+	 nop
+#endif
 	/* Log the event.  */
 	add	%sp, PTREGS_OFF, %o0
 	call	sun4v_resum_error
@@ -216,7 +219,10 @@
 	wrpr	%g0, 15, %pil
 	ba,pt	%xcc, etrap_irq
 	 rd	%pc, %g7
-
+#ifdef CONFIG_TRACE_IRQFLAGS
+	call		trace_hardirqs_off
+	 nop
+#endif
 	call	sun4v_resum_overflow
 	 add	%sp, PTREGS_OFF, %o0
 
@@ -295,7 +301,10 @@
 	mov	%g1, %g4
 	ba,pt	%xcc, etrap_irq
 	 rd	%pc, %g7
-
+#ifdef CONFIG_TRACE_IRQFLAGS
+	call		trace_hardirqs_off
+	 nop
+#endif
 	/* Log the event.  */
 	add	%sp, PTREGS_OFF, %o0
 	call	sun4v_nonresum_error
@@ -321,7 +330,10 @@
 	wrpr	%g0, 15, %pil
 	ba,pt	%xcc, etrap_irq
 	 rd	%pc, %g7
-
+#ifdef CONFIG_TRACE_IRQFLAGS
+	call		trace_hardirqs_off
+	 nop
+#endif
 	call	sun4v_nonresum_overflow
 	 add	%sp, PTREGS_OFF, %o0