sparc: Add kgdb support.

Current limitations:

1) On SMP single stepping has some fundamental issues,
   shared with other sw single-step architectures such
   as mips and arm.

2) On 32-bit sparc we don't support SMP kgdb yet.  That
   requires some reworking of the IPI mechanisms and
   infrastructure on that platform.

Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 2bd0340..ec4f5eb 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -29,3 +29,4 @@
 obj-$(CONFIG_AUDIT) += audit.o
 obj-$(CONFIG_AUDIT)$(CONFIG_COMPAT) += compat_audit.o
 obj-y += $(obj-yy)
+obj-$(CONFIG_KGDB) += kgdb.o
diff --git a/arch/sparc64/kernel/kgdb.c b/arch/sparc64/kernel/kgdb.c
new file mode 100644
index 0000000..fefbe6d
--- /dev/null
+++ b/arch/sparc64/kernel/kgdb.c
@@ -0,0 +1,186 @@
+/* kgdb.c: KGDB support for 64-bit sparc.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kgdb.h>
+#include <linux/kdebug.h>
+
+#include <asm/kdebug.h>
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+
+void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	struct reg_window *win;
+	int i;
+
+	gdb_regs[GDB_G0] = 0;
+	for (i = 0; i < 15; i++)
+		gdb_regs[GDB_G1 + i] = regs->u_regs[UREG_G1 + i];
+
+	win = (struct reg_window *) (regs->u_regs[UREG_FP] + STACK_BIAS);
+	for (i = 0; i < 8; i++)
+		gdb_regs[GDB_L0 + i] = win->locals[i];
+	for (i = 0; i < 8; i++)
+		gdb_regs[GDB_I0 + i] = win->ins[i];
+
+	for (i = GDB_F0; i <= GDB_F62; i++)
+		gdb_regs[i] = 0;
+
+	gdb_regs[GDB_PC] = regs->tpc;
+	gdb_regs[GDB_NPC] = regs->tnpc;
+	gdb_regs[GDB_STATE] = regs->tstate;
+	gdb_regs[GDB_FSR] = 0;
+	gdb_regs[GDB_FPRS] = 0;
+	gdb_regs[GDB_Y] = regs->y;
+}
+
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+	struct thread_info *t = task_thread_info(p);
+	extern unsigned int switch_to_pc;
+	extern unsigned int ret_from_syscall;
+	struct reg_window *win;
+	unsigned long pc, cwp;
+	int i;
+
+	for (i = GDB_G0; i < GDB_G6; i++)
+		gdb_regs[i] = 0;
+	gdb_regs[GDB_G6] = (unsigned long) t;
+	gdb_regs[GDB_G7] = (unsigned long) p;
+	for (i = GDB_O0; i < GDB_SP; i++)
+		gdb_regs[i] = 0;
+	gdb_regs[GDB_SP] = t->ksp;
+	gdb_regs[GDB_O7] = 0;
+
+	win = (struct reg_window *) (t->ksp + STACK_BIAS);
+	for (i = 0; i < 8; i++)
+		gdb_regs[GDB_L0 + i] = win->locals[i];
+	for (i = 0; i < 8; i++)
+		gdb_regs[GDB_I0 + i] = win->ins[i];
+
+	for (i = GDB_F0; i <= GDB_F62; i++)
+		gdb_regs[i] = 0;
+
+	if (t->new_child)
+		pc = (unsigned long) &ret_from_syscall;
+	else
+		pc = (unsigned long) &switch_to_pc;
+
+	gdb_regs[GDB_PC] = pc;
+	gdb_regs[GDB_NPC] = pc + 4;
+
+	cwp = __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP];
+
+	gdb_regs[GDB_STATE] = (TSTATE_PRIV | TSTATE_IE | cwp);
+	gdb_regs[GDB_FSR] = 0;
+	gdb_regs[GDB_FPRS] = 0;
+	gdb_regs[GDB_Y] = 0;
+}
+
+void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	struct reg_window *win;
+	int i;
+
+	for (i = 0; i < 15; i++)
+		regs->u_regs[UREG_G1 + i] = gdb_regs[GDB_G1 + i];
+
+	/* If the TSTATE register is changing, we have to preserve
+	 * the CWP field, otherwise window save/restore explodes.
+	 */
+	if (regs->tstate != gdb_regs[GDB_STATE]) {
+		unsigned long cwp = regs->tstate & TSTATE_CWP;
+
+		regs->tstate = (gdb_regs[GDB_STATE] & ~TSTATE_CWP) | cwp;
+	}
+
+	regs->tpc = gdb_regs[GDB_PC];
+	regs->tnpc = gdb_regs[GDB_NPC];
+	regs->y = gdb_regs[GDB_Y];
+
+	win = (struct reg_window *) (regs->u_regs[UREG_FP] + STACK_BIAS);
+	for (i = 0; i < 8; i++)
+		win->locals[i] = gdb_regs[GDB_L0 + i];
+	for (i = 0; i < 8; i++)
+		win->ins[i] = gdb_regs[GDB_I0 + i];
+}
+
+#ifdef CONFIG_SMP
+void smp_kgdb_capture_client(struct pt_regs *regs)
+{
+	unsigned long flags;
+
+	__asm__ __volatile__("rdpr      %%pstate, %0\n\t"
+			     "wrpr      %0, %1, %%pstate"
+			     : "=r" (flags)
+			     : "i" (PSTATE_IE));
+
+	flushw_all();
+
+	if (atomic_read(&kgdb_active) != -1)
+		kgdb_nmicallback(raw_smp_processor_id(), regs);
+
+	__asm__ __volatile__("wrpr	%0, 0, %%pstate"
+			     : : "r" (flags));
+}
+#endif
+
+int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
+			       char *remcomInBuffer, char *remcomOutBuffer,
+			       struct pt_regs *linux_regs)
+{
+	unsigned long addr;
+	char *ptr;
+
+	switch (remcomInBuffer[0]) {
+	case 'c':
+		/* try to read optional parameter, pc unchanged if no parm */
+		ptr = &remcomInBuffer[1];
+		if (kgdb_hex2long(&ptr, &addr)) {
+			linux_regs->tpc = addr;
+			linux_regs->tnpc = addr + 4;
+		}
+		/* fallthru */
+
+	case 'D':
+	case 'k':
+		if (linux_regs->tpc == (unsigned long) arch_kgdb_breakpoint) {
+			linux_regs->tpc = linux_regs->tnpc;
+			linux_regs->tnpc += 4;
+		}
+		return 0;
+	}
+	return -1;
+}
+
+asmlinkage void kgdb_trap(unsigned long trap_level, struct pt_regs *regs)
+{
+	unsigned long flags;
+
+	if (user_mode(regs)) {
+		bad_trap(regs, trap_level);
+		return;
+	}
+
+	flushw_all();
+
+	local_irq_save(flags);
+	kgdb_handle_exception(0x172, SIGTRAP, 0, regs);
+	local_irq_restore(flags);
+}
+
+int kgdb_arch_init(void)
+{
+	return 0;
+}
+
+void kgdb_arch_exit(void)
+{
+}
+
+struct kgdb_arch arch_kgdb_ops = {
+	/* Breakpoint instruction: ta 0x72 */
+	.gdb_bpt_instr		= { 0x91, 0xd0, 0x20, 0x72 },
+};
diff --git a/arch/sparc64/kernel/misctrap.S b/arch/sparc64/kernel/misctrap.S
index b257497..753b4f0 100644
--- a/arch/sparc64/kernel/misctrap.S
+++ b/arch/sparc64/kernel/misctrap.S
@@ -1,3 +1,13 @@
+#ifdef CONFIG_KGDB
+	.globl		arch_kgdb_breakpoint
+	.type		arch_kgdb_breakpoint,#function
+arch_kgdb_breakpoint:
+	ta		0x72
+	retl
+	 nop
+	.size		arch_kgdb_breakpoint,.-arch_kgdb_breakpoint
+#endif
+
 	.type		__do_privact,#function
 __do_privact:
 	mov		TLB_SFSR, %g3
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 409dd71..8face0c 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -910,6 +910,9 @@
 extern unsigned long xcall_report_regs;
 extern unsigned long xcall_receive_signal;
 extern unsigned long xcall_new_mmu_context_version;
+#ifdef CONFIG_KGDB
+extern unsigned long xcall_kgdb_capture;
+#endif
 
 #ifdef DCACHE_ALIASING_POSSIBLE
 extern unsigned long xcall_flush_dcache_page_cheetah;
@@ -1079,6 +1082,13 @@
 	smp_cross_call(&xcall_new_mmu_context_version, 0, 0, 0);
 }
 
+#ifdef CONFIG_KGDB
+void kgdb_roundup_cpus(unsigned long flags)
+{
+	smp_cross_call(&xcall_kgdb_capture, 0, 0, 0);
+}
+#endif
+
 void smp_report_regs(void)
 {
 	smp_cross_call(&xcall_report_regs, 0, 0, 0);
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index b0de4c0..450053a 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -153,7 +153,7 @@
 tl0_resv169:	BTRAP(0x169) BTRAP(0x16a) BTRAP(0x16b) BTRAP(0x16c)
 tl0_linux64:	LINUX_64BIT_SYSCALL_TRAP
 tl0_gsctx:	TRAP(sparc64_get_context) TRAP(sparc64_set_context)
-tl0_resv170:	KPROBES_TRAP(0x170) KPROBES_TRAP(0x171) BTRAP(0x172)
+tl0_resv170:	KPROBES_TRAP(0x170) KPROBES_TRAP(0x171) KGDB_TRAP(0x172)
 tl0_resv173:	BTRAP(0x173) BTRAP(0x174) BTRAP(0x175) BTRAP(0x176) BTRAP(0x177)
 tl0_resv178:	BTRAP(0x178) BTRAP(0x179) BTRAP(0x17a) BTRAP(0x17b) BTRAP(0x17c)
 tl0_resv17d:	BTRAP(0x17d) BTRAP(0x17e) BTRAP(0x17f)